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 } 