Android 自定义组件之 带有悬浮header的listview
最近做项目遇到一个需求,要做一个带有悬浮header的listview,即,当listview滑动时,header消失,静止时header浮现。
这个需求看似简单,实际做起来还是会遇到不少的困难,特此记录过程,以做记录。
首先,我们来看看需求,如下图。
有了需求,我们就可以开始做具体分析了,首先我们想到的是给listview添加一个滑动监听,在滑动时隐藏header在静止的时候就显示header。
关键代码如下:
1 list.setOnScrollListener(new AbsListView.OnScrollListener() { 2 @Override 3 public void onScrollStateChanged(AbsListView view, int scrollState) { 4 if(AbsListView.OnScrollListener.SCROLL_STATE_IDLE == scrollState){ 5 play(false,y); 6 } 7 if(AbsListView.OnScrollListener.SCROLL_STATE_FLING == scrollState){ 8 play(true,y); 9 } 10 if(AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL == scrollState) { 11 12 } 13 }其中play()就是我们的隐藏/显示 header的方法啦 写好了监听之后我们开始写隐藏/显示的PLAY()方法 首先我们来写一个简单的版本
private void play(boolean x,boolean y) { Animation animation; if(x){ animation = new AlphaAnimation(1,0); animation.setDuration(1000); textview.startAnimation(animation); textview.setVisibility(View.GONE); /* if(!y){ list.setPadding(0,0,0,0); deal(); }*/ } else{ textview.setVisibility(View.VISIBLE); animation = new AlphaAnimation(0,1); animation.setDuration(2000); textview.startAnimation(animation); View view = new View(this); } }可以看到我们通过第一个布尔参数来判断是隐藏还是显示。 做到这里看似已经完成了,但是有更多的细节是需要打磨的,由于我们采用的FrameLayout进行布局,当我们在顶部的时候会发现第一条记录被挡住了,这可不行。 不过我们可以通过设置listview的padding还解决,代码如下。 1 int i = textview.getLayoutParams().height; 2 list.setPadding(0,i,0,0); 现在运行我们的程序,好像已经完成了,但是这个时候可恶的BUG又出来捣乱了。 当我们只有少量记录(比屏幕显示多一条)的时候,会出现padding设置了之后无法还原的情况,这是因为虽然第一条记录被隐藏了一部分,但是并不是完全隐藏,所以不会触发listview的top事件。 这时候我们就需要在每次滑动的时候去检测滑动的距离,来判断是不是需要设置padding了,如果第一条记录都没有被隐藏,那么显然我们是不需要设置padding的。
1 private void deal() 2 { 3 View c = list.getChildAt(0); 4 int first = list.getFirstVisiblePosition(); 5 int top = c.getTop(); 6 int hight = c.getHeight(); 7 int distance = first*hight - top; 8 if(distance < hight) 9 { 10 int i = textview.getLayoutParams().height; 11 list.setPadding(0,i,0,0); 12 } 13 14 }这就是判断滑动距离的函数啦。 至此,一个简单的悬浮header listview已经完成了。 接下来是完整的布局和代码 布局:
1 <?xml version="1.0" encoding="utf-8"?> 2 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 tools:context=".MainActivity"> 6 7 <TextView 8 android:id="@+id/txt" 9 android:gravity="center" 10 android:background="#000" 11 android:text="Hello World!" 12 android:textColor="#0cbdb7" 13 android:textSize="40sp" 14 android:layout_width="match_parent" 15 android:layout_height="50dp" /> 16 <ListView 17 android:id="@+id/listview" 18 android:layout_width="match_parent" 19 android:layout_height="match_parent"/> 20 21 </FrameLayout>代码:
1 package com.example.administrator.listviewtest; 2 3 import android.app.Activity; 4 import android.support.v7.app.AppCompatActivity; 5 import android.os.Bundle; 6 import android.util.Log; 7 import android.view.View; 8 import android.view.ViewGroup; 9 import android.view.animation.AlphaAnimation; 10 import android.view.animation.Animation; 11 import android.widget.AbsListView; 12 import android.widget.ArrayAdapter; 13 import android.widget.BaseAdapter; 14 import android.widget.ListView; 15 import android.widget.SimpleAdapter; 16 import android.widget.TextView; 17 18 import java.util.ArrayList; 19 import java.util.List; 20 21 public class MainActivity extends Activity { 22 TextView textview; 23 ListView list; 24 boolean y = false; 25 @Override 26 protected void onCreate(Bundle savedInstanceState) { 27 super.onCreate(savedInstanceState); 28 setContentView(R.layout.activity_main); 29 list = (ListView)findViewById(R.id.listview); 30 textview = (TextView)findViewById(R.id.txt); 31 List<String> list1 = new ArrayList<>(); 32 for(int i = 0;i < 100;i++) 33 { 34 list1.add("record"+(i+1)); 35 } 36 ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_expandable_list_item_1,list1); 37 list.setAdapter(adapter); 38 39 list.setOnScrollListener(new AbsListView.OnScrollListener() { 40 @Override 41 public void onScrollStateChanged(AbsListView view, int scrollState) { 42 if(AbsListView.OnScrollListener.SCROLL_STATE_IDLE == scrollState){ 43 play(false,y); 44 } 45 if(AbsListView.OnScrollListener.SCROLL_STATE_FLING == scrollState){ 46 play(true,y); 47 } 48 if(AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL == scrollState) { 49 // play(true, y); 50 } 51 } 52 53 @Override 54 public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { 55 if(firstVisibleItem == 0) 56 { 57 Log.i("list","top"); 58 y = true; 59 int i = textview.getLayoutParams().height; 60 list.setPadding(0,i,0,0); 61 } 62 else 63 { 64 y = false; 65 } 66 } 67 }); 68 } 69 private void play(boolean x,boolean y) 70 { 71 Animation animation; 72 if(x){ 73 animation = new AlphaAnimation(1,0); 74 animation.setDuration(1000); 75 textview.startAnimation(animation); 76 textview.setVisibility(View.GONE); 77 if(!y){ 78 list.setPadding(0,0,0,0); 79 deal(); 80 } 81 } 82 else{ 83 textview.setVisibility(View.VISIBLE); 84 animation = new AlphaAnimation(0,1); 85 animation.setDuration(2000); 86 textview.startAnimation(animation); 87 View view = new View(this); 88 } 89 } 90 private void deal() 91 { 92 View c = list.getChildAt(0); 93 int first = list.getFirstVisiblePosition(); 94 int top = c.getTop(); 95 int hight = c.getHeight(); 96 int distance = first*hight - top; 97 if(distance < hight) 98 { 99 int i = textview.getLayoutParams().height; 100 list.setPadding(0,i,0,0); 101 } 102 103 } 104 }