Android Listview多tab上滑悬浮效果
样例
近期要做一个含有两个tab切换页面,两个页面有公共的描述信息区域,两个tab都是listview,可以向上或向下拉动刷新,在页面中部有一个tab切换区域,向上滑动的时候tab区域到顶部后就不在移动,向下拉又重新回到初始位置,先看一样样式图吧!
整个需求大致如上图所示,其中上拉刷新和下拉刷新没有截图,采用了开源控件pulltorefreshlistview来实现这个效果。
实现方式
总体思路,为了简单不想监控很多手势问题,因此投机取巧的采用下面的方式来实现,
a. 整个页面是一个listview,公共的区域作为listview的header添加进来,两个切换的tab也作为一个header加入,
b. 在页面布局的时候在listview上面添加一层,里面放tab的布局,这个tab的布局与listview的header中的是同一个布局,
c. 之后当listview滑动时候在onscroll函数中处理页面tab布局的显示与隐藏,当listview的tab布局到达屏幕顶部时,显示页面中的tab布局,向下滑动当整个tab都出现是影藏界面中的tab布局
d. tab切换,由于tab1,tab2的数据不同,因此采用了三个数据源,在tab切换的时候,数据来回切换,当点击tab时,记住当前显示的tab的pos和偏移量(只记住pos重定位的时候会有偏差)
demo的大致流程就是这样了,没有添加刷新的处理,虽然实际项目中时处理了更多的逻辑,但是demo不想写太复杂(主要是没有人看,就自己看,稍稍写写)。
说了这么多,可能看的人的还是不怎么明白,下面就来看代码吧
首先是界面布局,底层一个listview,顶部一个tab布局,界面布局up_float_first_activity.xml
<?xml version="1.0" encoding="utf-8"?> <framelayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@color/white_color" > <com.example.toolbox.upfloat.pulltorefreshlistview xmlns:ptr="http://schemas.android.com/apk/res-auto" android:id="@+id/up_float_listview" android:layout_width="fill_parent" android:layout_height="fill_parent" android:cachecolorhint="@color/white_color" android:divider="@color/transpant" android:dividerheight="0dip" android:fadingedge="none" android:fastscrollenabled="false" android:listselector="@color/transpant" android:smoothscrollbar="true" android:visibility="visible" ptr:ptrheadertextcolor="@color/color_333333" ptr:ptrmode="both" /> <include layout="@layout/up_float_tab_layout" android:visibility="gone" /> </framelayout>
tab布局,up_float_tab_layout.xml,text都采用了selector,这样在选中时可以高亮显示
<?xml version="1.0" encoding="utf-8"?> <linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/up_float_tab_root" android:layout_width="fill_parent" android:layout_height="wrap_content" android:background="@color/white_color" android:minheight="44dip" android:orientation="vertical" > <linearlayout android:layout_width="fill_parent" android:layout_height="44dip" android:minheight="44dip" android:orientation="horizontal" > <textview android:id="@+id/up_fload_tab1" android:layout_width="0dip" android:layout_height="match_parent" android:layout_weight="1" android:background="@drawable/show_event_detail_tab_selector" android:gravity="center" android:text="@string/up_float_tab1" android:textcolor="@color/show_event_detail_tab_text_selector" android:textsize="17sp" /> <textview android:id="@+id/up_float_tab2" android:layout_width="0dip" android:layout_height="match_parent" android:layout_weight="1" android:background="@drawable/show_event_detail_tab_selector" android:gravity="center" android:text="@string/up_float_tab2" android:textcolor="@color/show_event_detail_tab_text_selector" android:textsize="17sp" /> </linearlayout> <view android:layout_width="match_parent" android:layout_height="@dimen/split_one_pixels" android:background="@color/color_purple_bd6aff" /> </linearlayout>
公共部分布局up_float_common_layout.xml
<?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" android:background="@color/white_color" android:orientation="vertical" > <imageview android:id="@+id/show_event_detail_bg" android:layout_width="fill_parent" android:layout_height="125dip" android:contentdescription="@string/empty" android:scaletype="fitxy" android:src="@drawable/pic1" /> <textview android:id="@+id/show_event_detail_desc" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginbottom="24dip" android:layout_marginleft="15dip" android:layout_marginright="15dip" android:layout_margintop="24dip" android:text="@string/up_float_desc" android:textcolor="@color/color_black_333333" android:textsize="14sp" /> <view style="@style/horizontal_gray_divider" /> <view style="@style/horizontal_gray_divider" /> </linearlayout>
接下来就是主页面的代码了
package com.example.toolbox.upfloat.activity; import java.util.arraylist; import android.os.bundle; import android.support.v7.app.actionbaractivity; import android.view.layoutinflater; import android.view.view; import android.view.view.onclicklistener; import android.widget.abslistview; import android.widget.abslistview.onscrolllistener; import android.widget.arrayadapter; import android.widget.linearlayout; import android.widget.listview; import android.widget.textview; import com.example.toolbox.r; import com.example.toolbox.upfloat.pulltorefreshbase; import com.example.toolbox.upfloat.pulltorefreshbase.onrefreshlistener2; import com.example.toolbox.upfloat.pulltorefreshlistview; /** * * * @author sunyoujun * */ public class upfloatfirstactivity extends actionbaractivity implements onclicklistener { public static final int type_tab_1 = 1; public static final int type_tba_2 = 2; private int tab2pos = 0; private int tab2offsety = 0; private int tab1pos = 0; private int tab1offsety = 0; private arraylist<string> item = new arraylist<string>(); private arraylist<string> item1 = new arraylist<string>(); private arraylist<string> item2 = new arraylist<string>(); protected pulltorefreshlistview listview; private linearlayout titleview; private layoutinflater infater; private linearlayout titletab; private linearlayout titlefloattab; private textview latesttv; private textview latestfloattv; private textview hottv; private textview hotfloattv; private int currenttype = type_tab_1; private arrayadapter<string> adapter; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.up_float_first_activity); findviews(); setviewslistener(); updatetabselectstate(); initdata(); initlistview(); } private void findviews() { listview = (pulltorefreshlistview) findviewbyid(r.id.up_float_listview); titlefloattab = (linearlayout) findviewbyid(r.id.up_float_tab_root); latestfloattv = (textview) titlefloattab.findviewbyid(r.id.up_float_tab2); hotfloattv = (textview) titlefloattab.findviewbyid(r.id.up_fload_tab1); infater = layoutinflater.from(this); titleview = (linearlayout) infater.inflate(r.layout.up_float_common_layout, null); titletab = (linearlayout) infater.inflate(r.layout.up_float_tab_layout, null); latesttv = (textview) titletab.findviewbyid(r.id.up_float_tab2); hottv = (textview) titletab.findviewbyid(r.id.up_fload_tab1); } private void setviewslistener() { latesttv.setonclicklistener(this); hottv.setonclicklistener(this); latestfloattv.setonclicklistener(this); hotfloattv.setonclicklistener(this); updatetabselectstate(); } /** * 更新tab栏选中状态 */ private void updatetabselectstate() { boolean istab1 = (currenttype == type_tab_1); hottv.setselected(istab1); hotfloattv.setselected(istab1); latesttv.setselected(!istab1); latestfloattv.setselected(!istab1); } private void initdata() { for (int i = 1; i <= 50; i++) { item1.add("tab1-- item ---" + i); item2.add("tab2-- item ---" + i); } } private void initlistview() { setlistviewlistener(); listviewaddheader(); listviewloaddata(); } private void setlistviewlistener() { listview.setonrefreshlistener(new onrefreshlistener2<listview>() { @override public void onpulldowntorefresh(pulltorefreshbase<listview> refreshview) { // loadnews(); } @override public void onpulluptorefresh(pulltorefreshbase<listview> refreshview) { // loadolds(); } }); listview.setonscrolllistener(new onscrolllistener() { @override public void onscrollstatechanged(abslistview view, int scrollstate) { } @override public void onscroll(abslistview view, int firstvisibleitem, int visibleitemcount, int totalitemcount) { if (firstvisibleitem < 2) {// 悬浮tab出现时机,listview含有三个header titlefloattab.setvisibility(view.gone); } else titlefloattab.setvisibility(view.visible); ; } }); } private void listviewaddheader() { listview.getrefreshableview().addheaderview(titleview); listview.getrefreshableview().addheaderview(titletab); } protected void listviewloaddata() { item.clear(); item.addall(item1); adapter = new arrayadapter<string>(this, r.layout.list_item, android.r.id.text1, item); listview.setadapter(adapter); } @override public void onclick(view v) { switch (v.getid()) { case r.id.up_fload_tab1: switchtabtlist(true); break; case r.id.up_float_tab2: switchtabtlist(false); break; default: break; } } private void switchtabtlist(boolean istab1) { if (istab1) { if (currenttype == type_tab_1) { return;// 说明点击的是相同的活动列表,不用改变 } else {// tab2 switch tab1 tab2pos = listview.getrefreshableview().getfirstvisibleposition(); tab2offsety = getoffsety(); currenttype = type_tab_1; item2.clear(); item2.addall(item); item.clear(); item.addall(item1); } } else { if (currenttype == type_tba_2) { return; } else {// tab1 switch tab2 tab1pos = listview.getrefreshableview().getfirstvisibleposition(); tab1offsety = getoffsety(); currenttype = type_tba_2; item1.clear(); item1.addall(item); item.clear(); item.addall(item2); } } updatetabselectstate(); relocationlastpos(); } private int getoffsety(){ view view = listview.getrefreshableview().getchildat(0); return view != null ? view.gettop() : 0; } /** * 重新定位到上次的位置 */ private void relocationlastpos() { if (adapter != null) { adapter.notifydatasetchanged(); } if (currenttype == type_tab_1) { listview.post(new runnable() { @override public void run() { listview.getrefreshableview().setselectionfromtop(tab1pos, tab1offsety); } }); } else { listview.post(new runnable() { @override public void run() { listview.getrefreshableview().setselectionfromtop(tab2pos, tab2offsety); } }); } } }
总结:
a 上面的demo只是实现了向上滑动的效果,其实有很大的局限性,两个tab的item布局要一致,才能*切换,其次是两个tab不能左右滑动
b 上面的只适合两个或者一个tab,再多要控制的变量状态就更多,很容易出错,并且上面还没有包含刷新的效果,数据返回时不能仅仅是添加到item,而要判断刷新tab与当前显示tab的关系。
c 看了其他的开源项目,之后如果有时间会写一个demo,做真正的多个tab,并且能左右切换的效果。
ps: 鉴于还是有很多人要源代码,我就在下一篇重新实现了现有的方式,并且附上了git的代码地址,不要错过。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。