欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android Listview多tab上滑悬浮效果

程序员文章站 2024-02-29 20:42:34
样例        近期要做一个含有两个tab切换页面,两个页面有公共的描述信息区域,两个tab都是listv...

样例

       近期要做一个含有两个tab切换页面,两个页面有公共的描述信息区域,两个tab都是listview,可以向上或向下拉动刷新,在页面中部有一个tab切换区域,向上滑动的时候tab区域到顶部后就不在移动,向下拉又重新回到初始位置,先看一样样式图吧!

Android Listview多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的代码地址,不要错过。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。