#android #android-layout #android-ui
#android-layout #Android
Вопрос:
Я пытаюсь реализовать аналогичный эффект, подобный скользящему заголовку, похожему на iPhone, в приложении iPhone contact (скользящий заголовок, который группирует контакты по начальной букве).
Это экран моего приложения, и я хочу достичь следующего:
У меня есть «заголовок руководства» и три «вкладки» для сортировки списка. Когда пользователь прокручивает список вверх, я хочу, чтобы все прокручивалось вверх (заголовок руководства, вкладки, список). Однако, когда вкладки достигают верхней части экрана (и заголовок guide просто исчезнет с экрана), я хочу, чтобы вкладки останавливались и оставались там (оставались как «липкий заголовок»), и прокручивались только элементы списка, как в любом обычном представлении списка.
У меня есть группа просмотра (заголовок руководства) над списком.
Прежде всего, я хочу, чтобы заголовок guide изменял свое положение в зависимости от положения прокрутки в представлении списка.
Первый подход: Моя идея состояла в том, чтобы установить onScrollListener для представления списка и изменить верхнее поле заголовка guide на любое положение прокрутки первого элемента в представлении списка (что было бы отрицательным значением).
Логика правильная, но проблема, с которой я сталкиваюсь, заключается в том, что вид заголовка руководства перерисовывается недостаточно быстро при прокрутке в виде списка. Вид заголовка руководства обновляется только (до моего измененного значения верхнего поля), когда просмотр списка заканчивается. Даже медленная прокрутка не работает. Аннулирование (invalidate ()) вида заголовка руководства или его родительского элемента также не помогает, поскольку это просто поместило бы запрос на аннулирование в очередь, но аннулирование и перерисовка происходят не сразу, а только когда поток пользовательского интерфейса простаивает, чего, похоже, не происходит, пока пользователь все еще держит пальцы на просмотре списка прокрутки. Кажется, что запуск просмотра списка блокирует весь поток пользовательского интерфейса или делает его занятым сам по себе.
Итак, основная проблема заключается в том, что изменение поля в представлении заголовка руководства не становится видимым сразу, пока пользователь прокручивает представление списка. Код, который я использую, это:
@Override
public void onScroll(final AbsListView view, final int firstVisibleItem,
final int visibleItemCount, final int totalItemCount) {
// Get the first list item and check it's scroll position. This will be the value (top), that we also
// use the scroll the header parallel.
View v = mainList.getChildAt(0);
final int top = (v==null)?0:v.getTop();
// This logs the current scroll position of the first list item element/view group.
Log.d("onScroll", "onScroll: " top);
// Here we finally change the margin (setting a negative margin) to the header element.
((LinearLayout.LayoutParams)(findViewById(R.id.header_container).getLayoutParams())).setMargins(0, top, 0, 0);
// was just a test: invalidating the outer container/view group, doesn't help
// findViewById(R.id.ll_container).invalidate();
}
Я вижу вывод журнала «onScroll:», который я вставил в приведенный выше код в logcat, но следующая настройка верхнего поля просто не становится видимой.
Мой второй подход: заключается в использовании scrollview для заголовков вкладок руководства и работе с ними. Прокрутка заголовка руководства (который затем является видом прокрутки) из кода с помощью ScrollView.scrollTo(0,Math.abs(Math.abs (top)) из метода onScroll просмотра списка работает и почти сразу отображается на экране, однако это не очень точно / стабильно, когда пользователь запускает просмотр списка очень быстро — это означает, что он скачет с интервалами и не выглядит плавным; это только точно / стабильно при медленной прокрутке.
Теперь мой вопрос: существует ли какая-либо наилучшая практика для достижения такого эффекта скользящего заголовка и, более конкретно: есть ли способ принудительно перерисовать вид заголовка руководства, пока пользователь все еще прокручивает список (в моем первом упомянутом подходе).
Ответ №1:
Для этого вам следует использовать некоторые хитрости (afaik, готовой к использованию реализации такой функции не существует).
Например, вы могли бы обнаруживать жесты в вашем представлении и
- если текущий жест соответствует прокрутке вниз, и виден первый элемент списка, анимируйте-уменьшите размер заголовка до 0, размер представления вкладки до match_parent. Начинайте прокручивать список только тогда, когда заголовок больше не присутствует.
- если текущий жест соответствует прокрутке вверх, и первый уже виден, анимируйте — разверните заголовок до его первоначального размера.
Таким образом, использование анимации в представлении заголовка может быть вашим решением.
Обновить
Другим обходным путем было бы расширить ваш List
(массив значений вашего адаптера):
установите новый (фиктивный) элемент вверху для представления заголовка и измените ваш ListAdapter
getView
метод:
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
if (position == 0)
{
convertView = inflater.inflate(R.layout.sliding_header, parent,
false);
return convertView;
}
//TODO: your original method body comes here
}
где xml, на который ссылается R.layout.sliding_header
, должен содержать макет заголовка вашего списка.
Пользовательская OnScrollListener
реализация, применяемая к ListView
, сделала бы незаметным, что заголовок на самом деле является элементом списка, поскольку он скрывал бы полосу прокрутки.
Вы должны добавить этот прослушиватель к вашему listView
в onCreate
методе activity:
listView.setOnScrollListener(new MyScrollListener());
где MyScrollListener
находится:
/**
* Custom OnScrollListener
*/
private final class MyScrollListener implements OnScrollListener
{
@Override
public void onScrollStateChanged(AbsListView view, int scrollState)
{}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount)
{
if (view.getFirstVisiblePosition() == 0)
view.setVerticalScrollBarEnabled(false);
else if (!view.isVerticalScrollBarEnabled())
view.setVerticalScrollBarEnabled(true);
}
}
Комментарии:
1. Да, в этом определенно нет готового компонента для Android. Я надеялся, что кто-то, возможно, уже разработал такой проект с открытым исходным кодом, но ничего не нашел. О вашем предложении: Я также думал об анимации в начале, но снова отказался от идеи, потому что, если пользователь запускает список, мне нужно будет запускать пару анимаций одновременно, фактически для каждого изменения положения пикселя в списке. «анимировать — уменьшить размер заголовка до 0» и «анимировать — развернуть заголовок до исходного размера»: я не думаю, что это даст мне желаемый эффект, …
2. … конечная позиция сжатия анимации должна зависеть от текущей позиции прокрутки в виде списка. Например, если я прокрутил первый элемент списка только наполовину вверх (я имею в виду половину его высоты), то заголовок руководства также должен прокручиваться только на это количество (пикселей), еще не анимированный полностью. Но, возможно, я снова рассмотрю подход с анимацией, чтобы увидеть, работает ли он в целом лучше, чем изменение поля, касающееся блокировки потока пользовательского интерфейса при просмотре списка. Я просто боюсь, что анимация начнется только после завершения просмотра списка, а не во время него. Увидите.
3. Мне также нужно будет отменить все запущенные анимации, если я запускаю новую из-за изменения положения прокрутки в представлении списка. Звучит довольно сумбурно, но я попробую.
4. Я продолжал пытаться решить это менее болезненным / ресурсоемким способом, и в обновлении я опубликовал новое обходное решение (без использования явных анимаций), которое может сработать для вас.
5. Спасибо за ваше обновление, однако я последовал вашему совету с анимацией, установив длительность анимации равной 0. Анимации работают нормально, даже когда пользователь листает списки, поэтому кажется, что анимации не «заблокированы», а поток пользовательского интерфейса. Итак, теперь я закончил тем, что поместил свое руководство, вкладку и список в framelayout (все начинается сверху) и анимировал руководство и вкладки в прослушивателе прокрутки списка. UX более-менее приемлем, сейчас его тонкая настройка. Я проголосую за ваш ответ за подсказку по анимации.
Ответ №2:
Я думаю, вы также можете попробовать использовать мою ExpandAnimation для этого. http://udinic.wordpress.com/2011/09/03/expanding-listview-items
Просто передайте класс анимации, который отображает «направляющий заголовок», и пусть анимация сделает всю работу за вас, в этом случае прокрутка не требуется, и она плавная.