这个功能很是广泛了,主要是用户在下拉列表的时候,隐藏标题来扩大用户浏览列表的范围java
本方法的设计思路是在列表上覆盖标题栏,而后当列表滑到顶部的时候,在列表的顶部设置一个padding控件来占和标题同样的高度,防止列表顶部被标题覆盖,当列表往下滑动的时候,经过动画隐藏标题,只要列表的第一个item不可视,就把padding控件给隐藏掉,这样达到列表填充整个屏幕的效果android
先看布局ide
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:animateLayoutChanges="true" tools:context="com.example.showhidetitlelistview.MainActivity" > <View android:id="@+id/padding" android:layout_width="match_parent" android:layout_height="@dimen/title_height" /> <ListView android:id="@+id/listview" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@+id/padding" android:background="#F4F1F1" > </ListView> <LinearLayout android:id="@+id/titleLayout" android:layout_width="match_parent" android:layout_height="@dimen/title_height" android:background="@android:color/white" android:orientation="horizontal" > <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_weight="1" android:gravity="center" android:text="标题" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_weight="1" android:gravity="center" android:text="标题" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_weight="1" android:gravity="center" android:text="标题" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_weight="1" android:gravity="center" android:text="标题" /> </LinearLayout> </RelativeLayout>
listview在padding下方,而标题是在屏幕上方,覆盖全部控件布局
值得注意的是在根布局中设置的动画属性动画
android:animateLayoutChanges="true"this
缘由是设置padding控件消失会出现的时候,产生动画的效果,可是padding自己是透明的,因此我不关心它的效果如何(实际上,系统会给它一个淡入淡出的效果),我关心的是这个动画是占用必定时间的,列表在调整自身位置的时候,也会产生向上滑动的效果。网上有一些方法是经过设置根布局paddingtop属性,这个方法在调用的时候,listview会瞬间调整好当前的位置,致使屏幕闪了一下,若是用户缓缓向下滑动不松手的话,滑动某个位置触发了setpadding方法,屏幕会一直闪啊坑爹!设计
接着看代码code
/** * 因为标题是覆盖在列表上面的,须要设置一个padding来防止列表被标题被覆盖 */ public void setPadding() { padding.setVisibility(View.VISIBLE); } /** * 当列表往下滑动的时候,标题隐藏了,为了调整列表的高度使其填充整个屏幕,只须要去除padding控件便可 * 以前使用设置跟布局padding的方法,交互不友好,会闪屏,因此采起隐藏padding控件和根布局动画属性的方法 */ public void reMovePadding() { padding.setVisibility(View.GONE); }
/** * 隐藏标题,经过属性动画实现,和补间动画相比,属性动画真实改变了控件的位置,补间动画只是障眼法 * 我的比较嫌弃补间动画 */ private boolean isTitleMenuOpen=true; private int titleMenuHeight; public void hideTitle() { if (isTitleMenuOpen) { ObjectAnimator .ofFloat(titleLayout, "translationY", 0.0F, -titleMenuHeight).setDuration(300).start(); isTitleMenuOpen = false; } } /** * 显示标题 */ public void showTitle() { if (!isTitleMenuOpen) { ObjectAnimator .ofFloat(titleLayout, "translationY", -titleMenuHeight, 0.0F).setDuration(300).start(); isTitleMenuOpen = true; } }
在这里,细心的人就会发现,为何我不把设置padding控件和标题动画放在同一个方法里面呢?xml
这是由于他们的调用时机是有很大差异的,只有滑动的时候在执行标题动画,设置padding控件属性只能是列表第一个item可视的时候设置rem
否则每次滑动都调整padding,列表会莫名的滑动标题高度的距离,用户会崩溃的
下面是核心代码:
/** * 列表的滑动监听,关键在于监听列表是否滑动到顶部,若是是,就把padding控件显示出来,防止标题覆盖列表 * 其余状况下,隐藏padding,达到列表填充整个屏幕的效果 * 千万要记住,padding的出现和隐藏都会让列表的位置发生调整,这样给用户的体验不好,因此不要频繁调用setpadding和removepadding方法 */ private boolean isFirstVisiable=true; private OnScrollListener myOnScrollListener=new OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { // TODO Auto-generated method stub } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { // TODO Auto-generated method stub if (firstVisibleItem == 0) { setPadding(); showTitle(); isFirstVisiable=true; } else { reMovePadding(); isFirstVisiable=false; } } };
/** * 判断滑动方向,若是方向向上而且第一个item不可视,就隐藏标题 * 为何要判断第一个标题不可视呢,由于第一个标题可视是设置padding控件显示的关键, */ private float y_tmp1, y_tmp2; @Override public boolean onTouch(View v, MotionEvent event) { // 获取当前坐标 float y = event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: y_tmp1 = y; break; case MotionEvent.ACTION_MOVE: y_tmp2 = y; if (y_tmp1 != 0 && y_tmp2 != 0) { if (y_tmp1 - y_tmp2 > 8 &&! isFirstVisiable ) {// 向上滑动隐藏标题和导航栏 hideTitle(); Log.i("scolling", "向上滑动"); } if (y_tmp2 - y_tmp1 > 8) {// 向下滑动显示标题和导航栏 showTitle(); Log.i("scolling", "向下滑动"); } } break; } return false; }
在onCreate方法里面的一些初始化操做
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mContext = this; initData(); padding=findViewById(R.id.padding); titleLayout=findViewById(R.id.titleLayout); titleMenuHeight=getResources().getDimensionPixelSize(R.dimen.title_height); listview = (ListView) findViewById(R.id.listview); listview.addHeaderView(View .inflate(mContext, R.layout.item_blank, null)); listview.setAdapter(new Myadapter()); listview.setOnTouchListener(this); listview.setOnScrollListener(myOnScrollListener); }
以上操做基本实现了本博文题目的功能,可是有个问题,实际项目中,listview的item可能会很大,高度超过100dp的,当第一个item可视的时候,向上滑动,标题隐藏了,padding却不隐藏起来,由于它只有第一个item不可视的时候才隐藏啊,这就尴尬了。以前的东西就白看了呢!不用灰心!既然只要第一个可视的item不可视,padding就能隐藏起来对吧,那我来个瞒天过海,经过插入一个空白的头部就行了,而且这个头部很窄,只有1dp,只要手一滑动,基本就能把这个头部给划走,列表天然会填充整个屏幕;同理,当列表向下滑动的时候,只要这个很窄的头部出现,padding控件就会出现,列表的位置也调整过来了。这是比较取巧的地方!!!
源码:
http://pan.baidu.com/s/1c2Ntkas