ListView悬浮Header的简单实现
需求
如图,在某些情况下,我们可能会需要设计这样一种页面——页面中含有一个ListView,且要求页面中某一可滚动部分需要保持一直可见,即不会被滚动到屏幕之外,像是悬浮在页面上一样。
(如自定义布局的ListView标题栏,或者导航栏等)
有一个简单的实现方法就是,将其他可滚动部分、悬浮部分都作为ListView的header添加到ListView中,再给悬浮部分设置悬浮效果。
如何实现悬浮效果?我们先看看程序运行实例图
效果演示图
实现
实现悬浮部分的悬浮效果,思路其实很简单,就是把要悬浮的部分的layout复制成两份,一份添加到ListView中作为ListView的header(称为itemLayout),另一份则在页面布局中,与ListView放在同一个FrameLayout下(称为invisLayout),然后根据ListView当前滑动的位置,动态设置invisLayout显示与否。——当itemLayout未滚到屏幕顶部时,不显示invisLayout;当itemLayout滚到屏幕顶部、要滚出或已滚出屏幕时,显示invisLayout。
于是看起来就像某一控件悬浮在页面上一样,其实只是把它的分身显示出来而已。
如果被博主捉急的表达能力绕晕了,到现在还是弄不明白,那我们就直接来看代码吧
代码
首先先定义悬浮部分(invisLayout)的布局 invis_layout.xml,示例用的布局都很简单,具体根据自己的项目需求设计布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/invis_bg"
android:orientation="vertical" >
<TextView
android:layout_marginLeft="10dp"
android:text="这是悬浮部分"
android:textSize="18sp"
android:textColor="@color/white"
android:layout_margin="10dp"
android:id="@+id/tv_invis_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<LinearLayout
android:orientation="horizontal"
android:background="@color/white"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:layout_margin="10dp"
android:text="Button 1"
android:background="@drawable/btn_bg"
android:textSize="14sp"
android:textColor="@color/white"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:id="@+id/tv_invis_text1"/>
<Button
android:layout_margin="10dp"
android:text="Button 2"
android:background="@drawable/btn_bg"
android:textSize="14sp"
android:textColor="@color/white"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:id="@+id/tv_invis_text2"/>
</LinearLayout>
</LinearLayout>
这里博主给Button做了一个美化,简单地设置Button控件外围弧度和背景颜色,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="false">
<shape>
<solid android:color="@color/btn_press_color"/>
<corners android:radius="8dp"/>
</shape>
</item>
<item android:state_pressed="true">
<shape>
<solid android:color="@color/btn_pressed_color"/>
<corners android:radius="8dp"/>
</shape>
</item>
</selector>
然后是页面其他可滚动的部分(不需要悬浮的部分)的布局header_layout.xml,这里也很简单只是一个TextView
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<TextView
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="#cccccc"
android:gravity="center"
android:text="这是其他可滚动头部内容" />
</LinearLayout>
然后是主界面的布局文件activity_invis_demo.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="30dp"
android:background="#332b3b"
android:textColor="@color/white"
android:gravity="center"
android:text="页面固定头部" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/title" >
<ListView
android:id="@+id/lv"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<include layout="@layout/invis_layout"
android:visibility="gone"
android:id="@+id/invis_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</FrameLayout>
</RelativeLayout>
这里就是把悬浮部分(invis_layout)和ListView放在同一个FrameLayout下面,并默认不显示悬浮部分,在程序中实现OnScrollListener#onScroll()方法,控制悬浮部分的显示时间。
最后是程序代码InvisDemoActivity
public class InvisDemoActivity extends Activity {
//listView
private ListView lv;
//悬浮部分layout
private LinearLayout invisLayout;
//store listview data
private String[] strs;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_invis_demo);
//取得悬浮部分(invisLayout)
invisLayout = (LinearLayout) findViewById(R.id.invis_layout);
strs = new String[20];
for (int i = 0; i < 20; i++) {
strs[i] = "data-----" + i;
}
//取得listView
lv = (ListView) findViewById(R.id.lv);
//取得页面可滚动的其他部分
View header = View.inflate(this, R.layout.header_layout, null);
//添加到listView头部
lv.addHeaderView(header);
//取得ListView条目中的悬浮部分(itemLayout),并将其添加到头部
lv.addHeaderView(View.inflate(this, R.layout.invis_layout, null));
lv.setAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, strs));
//监听listView滚动状态
lv.setOnScrollListener(new OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
//动态控制是否显示invisLayout
@Override
public void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) {
if (firstVisibleItem >= 1) {
invisLayout.setVisibility(View.VISIBLE);
} else {
invisLayout.setVisibility(View.GONE);
}
}
});
}
}
到这里我们就实现了ListView的悬浮头部,大家可以自己试试写个demo,有问题可评论或者发邮件跟我联系yetwish@gmail.com