SwipeRefreshLayout: не сферический и не в вакууме

от автора

Про новый SwipeRefreshLayout из библиотеки Android support на Хабре уже писали, да и Google любезно выдаёт множество ссылок на подобные примеры. Их всех объединяет одно — в SwipeRefreshLayout добавляется единственное TextView или ListView, и через минуту разработчик с умилением глядит на работающую анимацию. А если нам интерфейс чуть посложнее надо?

Итак, у нас есть Activity с двумя элементами: сверху — панель фильтра, снизу — некое View (лишние теги удалены):

<LinearLayout android:layout_width="match_parent"     android:layout_height="match_parent"     android:orientation="vertical" >     <fragment         android:layout_width="match_parent"         android:layout_height="wrap_content" />     <com.mycompany.MyView         android:layout_width="match_parent"         android:layout_height="match_parent" /> </LinearLayout> 

Нам всего-то нужно заменить LinearLayout на SwipeRefreshLayout. Точнее, просто заменить не получится — SwipeRefreshLayout позволяет иметь только один вложенный элемент. Давайте просто обернём LinearLayout в SwipeRefreshLayout:

<android.support.v4.widget.SwipeRefreshLayout     android:layout_width="match_parent"     android:layout_height="match_parent" >     <LinearLayout android:layout_width="match_parent"     android:layout_height="match_parent"     android:orientation="vertical" >         <fragment         android:layout_width="match_parent"         android:layout_height="wrap_content" />         <com.mycompany.MyView         android:layout_width="match_parent"         android:layout_height="match_parent" />     </LinearLayout> </android.support.v4.widget.SwipeRefreshLayout> 

Запускаем — работает! Правда, как-то странно работает: индикатор обновления то не появляется, то пропадает.

Материмся, гуглим, изучаем опыт предыдущих поколений. Оказывается, в SwipeRefreshLayout что попало класть нельзя. ScrollView можно, GridView можно, ListView можно, а больше ничего и нельзя. ListView и GridView нам совсем не подходят, а вот ScrollView можно попробовать. Оборачиваем наш многострадальный LinearLayout в ScrollView:

<android.support.v4.widget.SwipeRefreshLayout      android:layout_width="match_parent"     android:layout_height="match_parent" >     <ScrollView         android:layout_width="match_parent"         android:layout_height="match_parent" >         <LinearLayout             android:layout_width="match_parent"             android:layout_height="wrap_content"             android:orientation="vertical" >             <fragment android:layout_width="match_parent"                 android:layout_height="wrap_content" />             <com.mycompany.MyView                 android:layout_width="match_parent"                 android:layout_height="match_parent" />         </LinearLayout>     </ScrollView> </android.support.v4.widget.SwipeRefreshLayout> 

Обращаем внимание — Lint тут же требует изменить android:layout_height с match_parent на wrap_content у вложенных в ScrollView элементов.

Запускаем, и… видим только панель фильтра. А где же нижний View? А нет его. Точнее, он есть, но мы его не видим. Раньше LinearLayout растягивал его на всё свободное пространство благодаря match_parent, но теперь-то мы внутри ScrollView! А ScrollView потому и ScrollView, что никого внутри себя растягивать не собирается, потому что его содержимое может выходить за пределы самого ScrollView.

Выход — наше нижнее MyView должно само себя посчитать, то есть определить свою высоту, основываясь на высоте родительского Activity:

@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 	ViewParent llp = getParent(); // LinearLayout 	View swp = (View) llp.getParent(); // ScrollView 	View srlp = (View) swp.getParent(); // SwipeRefreshLayout  	int measuredWidth = getDefaultSize(getSuggestedMinimumWidth(), 		widthMeasureSpec); 	int measuredHeight = srlp.getMeasuredHeight(); 	int orientation = getResources().getConfiguration().orientation; 	if (orientation == Configuration.ORIENTATION_PORTRAIT) { 	    View filter = swp.findViewById(R.id.frFilter); 	    int fh = filter.getMeasuredHeight(); 	    measuredHeight -= fh; 	} 	setMeasuredDimension(measuredWidth, measuredHeight); } 

Очень некрасивое решение. Зато работает. Гламурных всем анимаций!

ссылка на оригинал статьи http://habrahabr.ru/post/256947/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *