Listview多tab上滑悬浮

extends:http://blog.163.com/[email protected]/blog/static/37250245201410541721892/

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

整个需求大致如上图所示,其中上拉刷新和下拉刷新没有截图,采用了开源控件PullToRefreshListView来实现这个效果。

2:总体思路,为了简单不想监控很多手势问题,因此投机取巧的采用下面的方式来实现,

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不想写太复杂(主要是没有人看,就自己看,稍稍写写)。

3:说了这么多,可能看的人的还是不怎么明白,下面就来看代码吧

a. 首先是界面布局,保护两层,底层一个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>

b. 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>

c .公共部分布局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>

d.接下来就是主页面的代码了

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);
}
});
}
}

}

4. 总结,

a .  上面的demo只是实现了向上滑动的效果,其实有很大的局限性,两个tab的item布局要一致,才能自由切换,其次是两个tab不能左右滑动

b .  上面的只适合两个或者一个tab,再多要控制的变量状态就更多,很容易出错,并且上面还没有包含刷新的效果,数据返回时不能仅仅是添加到item,而要判断刷新tab与当前显示tab的关系。

c .   看了其他的开源项目,之后如果有时间会写一个demo,做真正的多个tab,并且能左右切换的效果。

ps: 鉴于还是有很多人要源代码,我就在下一篇重新实现了现有的方式,并且附上了git的代码地址

时间: 2024-11-09 10:50:00

Listview多tab上滑悬浮的相关文章

RecyclerView 滑动检测 (上滑 up)(下滑 down)(顶部 top)(底部 bottom)

RecyclerView 给我们的可以检测滑动事件的接口 只有 一个方法 recyclerview.setOnScrollListener()或者 recyclerview.addOnScrollListener() set方法将会被弃用 deprecated 最好使用add方法但是这个也可以根据自己情况,如果自己当前的api中set方法没有被弃用,不存在add方法.就只能使用set方法了. 监听 上滑,下滑 这些都不是重点,接下来就分析如何监听,RecyclerView的滑动. Recycle

Android ListView下拉/上拉刷新:设计原理与实现

 <Android ListView下拉/上拉刷新:设计原理与实现> Android上ListView的第三方开源的下拉刷新框架很多,应用场景很多很普遍,几乎成为现在APP的通用设计典范,甚至谷歌官方都索性在Android SDK层面支持下拉刷新,我之前写了一篇文章<Android SwipeRefreshLayout:谷歌官方SDK包中的下拉刷新>专门介绍过(链接地址:http://blog.csdn.net/zhangphil/article/details/4696537

Android 上滑显示底部导航,下滑显示标题bar

本文简单介绍使用属性动画来实现上滑显示底部导航,下滑显示标题bar.先上图看效果,再分析: 可以看出这是个listview有标题和底部,有点像下拉刷新和上拉加载更多.只不过下拉或上拉一定时位置固定拉不动,且只在list的第一个item出现显示时,才平滑动画的让标题或底部显示或隐藏. 实现思路: 1.整个布局有三个部分构成,上部由一个RelativeLayout放ImageView或TextView.中间部分是个listView,下部是一个TextView. 2.采用LinearLayout摆放中

阻止用户双击使屏幕上滑

/*阻止用户双击使屏幕上滑*/var agent = navigator.userAgent.toLowerCase();        //检测是否是iosvar iLastTouch = null;                                //缓存上一次tap的时间if (agent.indexOf('iphone') >= 0 || agent.indexOf('ipad') >= 0){    document.body.addEventListener('tou

解决上滑过程中数据重复的问题

问题:最近在做微信小程序的某个项目,手机屏幕上,手指上滑加载更多数据的时候,老是出现重复的数据. 解决方案:状态锁和函数节流. 原理:在向服务器请求数据的时候和接收返回的数据,改变某个变量的状态以及延迟函数的执行. 具体代码: var moreStatus=false; var timeoutId=null; performProcessing: function(){ if(!moreStatus){ moreStatus=true; // 开始向服务器请求数据代码,成功向服务器请求数据之后,

关于移动端开发时iOS上滑屏卡顿的问题,以及电话类数字的样式失控问题

写在前面的话: tips:写移动的时候,那些头部需要固定显示在显示屏顶部的,通常在PC端我会用fixed来写.但是,在移动端,这并不是一个好方法,因为弹出输入小键盘的时候,会造成fixed 的元素偏移掉,在这里有两种方法可以解决: 1.建议移动端布局采用以下方式(见正文),如果有错误的地方,还请指正~ 2.另外还看到一篇文章提到这个问题,作者让固定的头部仍然采用fixed, 然后内容区也用了fixed,内容区的fixed元素这样写:{position:fixed;top:80px;bottom:

iOS 实现长按录音上滑取消的几种思路

body { font-size: 13pt; color: #222; background: #fbfbfb; font-family: "Helvetica Neue", Arial, Helvetica, sans-serif; line-height: 1.4; margin: 10% } h1,h2,h3,h4,h5,h6 { font-weight: normal; color: #111 } h1 { font-size: 3em; line-height: 1; ma

Android如何定制一个下拉刷新,上滑加载更多的容器

前言 下拉刷新和上滑加载更多,是一种比较常用的列表数据交互方式. android提供了原生的下拉刷新容器 SwipeRefreshLayout,可惜样式不能定制. 于是打算自己实现一个专用的.但是下拉刷新和上滑,非常考验对android布局与父子触摸机制的功底,因此参考gitHub上的一个热门的下拉刷新项目 之所以选择他是因为它一个类就完成了所有View的适配,非常的精简强力. 需求 咱对下拉刷新.上滑加载更多的控件,需求如下: 1:下拉刷新,拖动到一定距离,提示文字变成 放手刷新 2:刷新完成

网站中图片上滑出现说明文字的特效

网站中为了美观也为了可以在一个区域中展示的信息更多的原因,可以看到很多图文混杂的特效. (这个的目标是单位面积上呈现给用户的信息量最多) 比如鼠标放到图片上,然后图片翻转到背面,而背面是图片的介绍信息 比如鼠标放到图片上,然后从图片的下端或者任一端弹出对应介绍信息的图层,图片位置不变 比如鼠标放到图片上,然后图片上移紧随着的是介绍信息的显示 这篇博客是讲的以上说到的第三种比如. 图片特效展示如下: 起先:鼠标放上去:最后是: 原理: 这里a标签就包括图片和文字,其实图片和文字是一个整体,可以理解