Страницы

Поиск по вопросам

понедельник, 3 декабря 2018 г.

Размещение нескольких элементов в видимой области ViewPager

Есть данный макет. Область на которой находятся Card'ы. При свайпе справа-налево должны отображться следующие 2 элемента. Я делаю это с помощью ViewPager, но проблема в том, что ViewPager размещает по одному элементу в видимую область. Как решить эту проблему?


Ответ

Не претендую на завершенное решение, но кажется должна сработать такая идея.
Все карды кладутся в горизонтальный LinearLayout, который оборачивается в HorizontalScrollView



Это даст нам возможность скроллить карды по горизонтали.
Теперь нужно изменить ширину кардов так, чтобы на экран помещалось два карда. Для этого можно, например, унаследоваться от Card и переопределить onMeasure
public class MyCard extends Card { // …
@Override protected void onMeasure(int widthMeasureSpec, final int heightMeasureSpec) {
final View parentScrollView = ((View)(getParent().getParent()));
if (parentScrollView != null) { if (parentScrollView instanceof HorizontalScrollView) { widthMeasureSpec = parentScrollView.getMeasuredWidth() / 2; } } setMeasuredDimension(widthMeasureSpec, heightMeasureSpec); } }
Останется по событию скролла вычислить ближайшую позицию скролла, в которой на экране будут отображаться два карда целиком и вручную доскроллить через HorizontalScrollView.fullScroll(…)

Межкомпонентная связь React: как передавать данные между компонентами?

Здравствуйте! Вопрос касается связи между компонентами React,а именно: передача данных из одного компонента в другой.
Пусть есть страница , у которой есть массив объектов items. Для каждого элемента items создается компонент
Код Layout.jsx:
class Layout extends Component { renderItems() { var items = [ {name: 'Ivan', _id: '1'}, {name: 'Petya', _id: '2'} ];
return items.map( (each) => { return ( ); }); }
render() { return (

{this.renderItems}
); } }
Код Item.jsx:
class Item extends Component { render() { return (
{this.props.each.name}
); } }
Пусть теперь я хочу реализовать по щелчку на каждый вывод в консоль его _id. Сделать это внутри самого не составляет никакого труда:
Новый код Item.jsx:
class Item extends Component { printId() { console.log(this.props.each._id); }
render() { return (
{this.props.each.name}
); } }
Но как быть, если нужно реализовать кнопку "Показать _id" снаружи, то есть в ?
Допустим, внутри каждого добавим checkbox. Если этот чекбокс отмечен галочкой как selected, то при нажатии кнопки 'Показать _id' в консоль выводятся _id всех отмеченных Itemов.
Но как передать _id отмеченных Itemов в ?
Заранее благодарен за ответы.


Ответ

Ответ нашелся сразу в документации, спасибо @AlexeyTen за наводку. Пришлось помучиться, однако решение готов и оно ниже.
При вызове функции из компонента someFunction.bind(this) мы можем передавать любое количество аргументов: someFunction.bind(this, arg1, arg2, ...). В этом и заключается ответ.
Для примера выше: добавим функцию printId в компонент и навесим на компонент вызов printId по событию onClick. В качестве аргумента в функцию будем передавать текущий _id элемента. Новый код Layout.jsx:
class Layout extends Component { printId(id) console.log(id);
renderItems() { var items = [ {name: 'Ivan', _id: '1'}, {name: 'Petya', _id: '2'} ];
return items.map( (each) => { const eachId = each._id; return ( ); }); }
render() { return (

{this.renderItems}
); } }
Однако, код выше не будет работать. Причина в том, что это не настоящий DOM-элемент, соответственно и события OnClick у него быть не может. В строке onCLick является обычным props. Для того, чтобы этот код работал, как ожидается, нужно внутри компонента у настоящего DOM-элемента прописать передачу настоящему onClick нашу функцию из props
class Item extends Component { render() { return (
{this.props.each.name}
); } }
Теперь все работает как надо.

На что влияет адрес хоста у создателя подпрограммы в MySQL?

На что влияет адрес хоста у создателя подпрограммы в MySQL? Например, при создании подпрограммы (хранимой процедуры, функции, триггера и т.д.) определяется создатель подпрограммы (DEFINER):
CREATE DEFINER = 'admin'@'localhost' PROCEDURE p1() SQL SECURITY DEFINER BEGIN UPDATE t1 SET counter = counter + 1; END;
На что тогда влияет адрес? Например, что бы изменилось, если бы вместо 'admin'@'localhost' тут было 'admin'@'%'?


Ответ

DEFINER просто говорит базе, какой контекст безопасности использовать при выполнении процедуры. Если он стоит как DEFINER - привилегии берутся для аккаунта, который создал процедуру, а если стоит INVOKER - то тогда привилегии, как у того, кто вызвал.
CREATE DEFINER = 'admin'@'localhost' PROCEDURE p1() SQL SECURITY DEFINER BEGIN UPDATE t1 SET counter = counter + 1; END;
Любой пользователь, который имеет привилегию EXECUTE на над процедурой p1 может вызвать ее с помощью оператора CALL. Однако, когда p1 выполняется, она делает это в контексте безопасности DEFINER и, следовательно, выполняется с привилегиями 'admin'@'localhost' , учетной записи, указанной в атрибуте DEFINER. Эта учетная запись должна иметь привилегию EXECUTE для p1 , а также UPDATE привилегии для таблицы t1 . В противном случае, процедура не выполняется из-за отсутствия достаточных привилегий.
Адрес говорит вам о том, что будут использованы привелегии определенные для пользователя 'admin'@'localhost. Тоесть пользователя admin который подключается с localhost, в MYSQL разграничение доступа осуществляется по имени пользователя и адресу с которого идет подключение, для пользователя admin с localhost можно установить GRANT ALL а для других хостов только SELECT например.
Пользователи 'admin'@'localhost' и 'admin'@'%' - это совершенно разные аккаунты.

Прогресс скроллинга страницы. Как сделать?

Есть лендинг с фиксированным хедером. Нужно чтобы в нем отображалась полоса прогресса скроллинга по странице, а именно по разделам. Как это осуществить?


Ответ

var bar = $('#bar'), $window = $(window), docHeight = $(document).height(), winHeight = $window.height(), baseX = docHeight - winHeight; $window.scroll(function(e) { var x = ($window.scrollTop() / baseX) * 100; bar.css({'width': + x + '%'}); }); body{ height:4000px; } ul { list-style-type: none; padding: 0; margin: 0; overflow: hidden; } a { text-decoration: none; } ul li { display: block; float: left; } ul li a { display: block; padding: 1rem 2rem; font-family: sans-serif; } .nav { display: block; width: 100%; border-bottom: 2px solid #ccc; position: relative; position: fixed; } #bar{ position:absolute; left: 0; bottom: -2px; background-color:red; width: 0px; height: 2px; }​


Вариант с якорями:
var bar = $('#bar'), $window = $(window), docHeight = $(document).height(), winHeight = $window.height(), baseX = docHeight - winHeight; var lastId, topNav = $(".nav"), topNavHeight = topNav.outerHeight(), link = topNav.find("a"); scrollItems = link.map(function(){ var item = $($(this).attr("href")); if (item.length) { return item; } }); $window.scroll(function(e) { var x = ($window.scrollTop() / baseX) * 100; bar.css({'width': + x + '%'}); var fromTop = $(this).scrollTop()+topNavHeight; var cur = scrollItems.map(function(){ if ($(this).offset().top < fromTop) return this; }); cur = cur[cur.length-1]; var id = cur && cur.length ? cur[0].id : ""; if (lastId !== id) { lastId = id; link .parent().removeClass("active") .end().filter("[href='#"+id+"']").parent().addClass("active"); } }); body{ height:4000px; padding-top: 5rem; } ul { list-style-type: none; padding: 0; margin: 0; overflow: hidden; } a { text-decoration: none; } ul li { display: block; float: left; } ul li a { display: block; padding: 1rem 2rem; font-family: sans-serif; } .nav { display: block; width: 100%; border-bottom: 2px solid #ccc; position: relative; position: fixed; top: 0; } #bar{ position:absolute; left: 0; bottom: -2px; background-color:red; width: 0px; height: 2px; } .box { height: 20rem; padding: 2rem; line-height: 1.5rem; } .active a{ background: red; color: #fff; }
1 Lorem ipsum dolor sit amet, consectetur adipisicing elit. A, excepturi.
2 Lorem ipsum dolor sit amet.
3 Lorem ipsum dolor sit amet, consectetur adipisicing elit. Temporibus, at debitis! Fuga, architecto, illum. Deleniti optio voluptatibus suscipit veniam, dicta.

Отучить KDE автозапускать последние приложения

Задача такая: отучить KDE автостартовать приложения, которые были запущены в предыдущей сессии. Сами приложения не прописаны в автозапуске, KDE их запускает сам. Искал по всем настройкам, в гугле, ответа не нашел. Как отучить KDE автозапускать последние приложения?


Ответ

Оказалось, эта настройка запрятана в "Управлении сеансами", что в разделе "Запуск и завершение". Мне и в голову не могло придти искать эту функцию там, так как я считал, что сеансы связаны исключительно с входом нескольких пользователей в систему. Итого,что бы отключить эту фитчу идем в "Параметры системы" -> "Запуск и завершение" -> "Управление сеансами" и ставим "Начинать с пустого сеанса".

Масштабирование интерфейса WPF

Было разработано приложение с использованием WPF.
Заказчик использует приложение на планшете и интерфейс мелковат для быстрой работы, требуется увеличить все элементы, ну скажем, на 50%.
Как сделать это быстро и с меньшими затратами? В каждом Window применить к контейнеру компоновки трансформацию Scale в RenderTransform? Попробовал сделать это на примере одного из Window - окно и не знает, что содержимое увеличилось и оно в окно не влезает...
Как всё-таки правильно это сделать? На что при этом обратить внимание? А, может быть, есть способ сделать масштабирование динамическим с возможностью смены коэффициента во время работы (при работе с мышью ведь увеличение и не требуется)?


Ответ

Ну, если решать проблему так, как вы хотите (масштабированием интерфейса), то подойдёт следующая идея. Пусть вы увеличиваете всё в k раз (у вас k = 1.5). Пишем так:



(С удивлением обнаружил, что RenderTransform перемещает область hit test.)

Однако мне кажется, что это не идеальное решение. Дело в том, что простое скалирование интерфейса не поможет. Майкрософт пробовала в ранних версиях Windows Phone скалирование десктопных интерфейсов, и отказалась от этого: при таком подходе страдает usability.
Когда у вас мало места на экране, вы захотите не скалировать всё, а расположить элементы по-другому. Поэтому лучше следовать опыту Microsoft, и сделать для планшетов отдельный интерфейс, похожий на основной, но «заточенный» под меньший размер экрана и тач-управление. Будет выглядеть намного профессиональнее.

Дополнение: Если вам нужно менять размер в зависимости от разных обстоятельств, проще всего сделать его параметром. Это делается так:
В MainWindow кладём DependencyProperty типа double, назовём его ScalseFactor. Значение по умолчанию — 1.0
public double ScaleFactor { get { return (double)GetValue(ScaleFactorProperty); } set { SetValue(ScaleFactorProperty, value); } }
public static readonly DependencyProperty ScaleFactorProperty = DependencyProperty.Register( "ScaleFactor", typeof(double), typeof(MainWindow), new PropertyMetadata(1.0)); Вместо константы 1.5 в ScaleY прописываем привязку:
{Binding ScaleFactor, ElementName=Main}
(даём окну имя Main, чтобы было проще привязывать). Для привязки ColumnDefinition нам нужно вычесть единицу и перейти от double к типу GridLength, поэтому используем конвертер. Для начала определим его:
class RestGridLengthConverter : IValueConverter { public object Convert(object value, Type tt, object parameter, CultureInfo ci) { return new GridLength((double)value - 1, GridUnitType.Star); }
public object ConvertBack(object value, Type tt, object parameter, CultureInfo ci) { throw new NotImplementedException(); } }
Кладём в ресурсы и привязываем:
Всё, теперь у нас можно настраивать увеличение при старте программы (или вообще когда угодно), используя ScaleFactor
Например, можно прикрутить к нему слайдер. Вот полный пример:


namespace Example { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); }
public double ScaleFactor { get { return (double)GetValue(ScaleFactorProperty); } set { SetValue(ScaleFactorProperty, value); } }
public static readonly DependencyProperty ScaleFactorProperty = DependencyProperty.Register( "ScaleFactor", typeof(double), typeof(MainWindow), new PropertyMetadata(1.0)); } }

namespace Example { class RestGridLengthConverter : IValueConverter { public object Convert(object value, Type tt, object parameter, CultureInfo ci) { return new GridLength((double)value - 1, GridUnitType.Star); }
public object ConvertBack(object value, Type tt, object parameter, CultureInfo ci) { throw new NotImplementedException(); } } }
Результат:

Как настроить функцию передвижения кружочка?

Есть функция которая отвечает за перемещение, кружочка по тач-событиям. Но проблема в том, что курсор то обгоняет сам кружочек то отстает.
Как сделать так, чтоб кружочек двигался равномерно, вслед за пальцем при этом не обгонял и не отставал ?
Сам код :
var target; $('.circle').on("touchstart", function() { target = $(this); }); var moove = function (obj, x, y){ $(obj).css({"left" : x }); $(obj).css({"top" : y }); } $(window).on("touchmove", function(e) { moove($(target), event.targetTouches[0].screenX, event.targetTouches[0].screenY ); }); .circle { width: 50px; height: 50px; border-radius: 100%; background: green; position: absolute; }


фидл: https://jsfiddle.net/dxnxpybe/21/


Ответ

А Вы пробовали изменить screenX и screenY на clientX clientY, вроде как кружочек следует за пальцем.
var target;
$('.circle').on("touchstart", function() { target = $(this); });
var moove = function (obj, x, y){ $(obj).css({"left" : x }); $(obj).css({"top" : y }); }
$(window).on("touchmove", function(e) { moove($(target), event.targetTouches[0].clientX, event.targetTouches[0].clientY ); });
https://jsfiddle.net/appcscme/1/