利用ListView实现最简单的上滑悬停 (附源码)
来源:互联网 发布:水产加工erp软件 编辑:程序博客网 时间:2024/05/01 14:17
笔者之前在做一个项目的时候,需要实现一个特殊效果的布局,即列表顶部的布局能“下拉悬停”,也就是说,当列表往上滑动的时候,列表顶部的布局,能悬停在屏幕顶部,而不被滑出屏幕。
如图所示:当列表滑动时,搜索框也能随着滑动,然而搜索框无论如何却不会滑出布局之外,而是能悬停在顶部。
原理很简单,其实,搜索框布局一直都是随着列表滑动的,只是,当搜索框布局滑动到屏幕上边缘时,意味着该布局即将被挡住,这时候及时在布局顶部添加一个一模一样的布局(笔者称为替代布局),覆盖了原来的布局,所以,原先的搜索框布依旧就会被滑出布局外,然而由于替代布局至于布局顶部,所以会产生其该布局总是顶再屏幕上方的错觉。
笔者在下图中显示了布局边界,希望可以帮助各位更清晰地描述这一点。
所以这里就要解决一个问题:
如何知道搜索框布局在什么时候即将滑出屏幕边缘?
首次,笔者发现,在ListView,中,有个addHeaderView(View v) 方法,该方法可以让使用者添加任意特殊的View到ListView的顶部成为特殊的列表项,使得该特殊的View可以随着ListView的列表项一起滑动,并且可以添加多了列表项。笔者在demo中,就把搜索框布局通过该方法添加到ListView的顶部,使其成为ListView的列表项。这样做的好处是什么,答案在下面:
其次,我们可以为ListView注册滑动监听器:
ListView listView; //..... listView.setOnScrollListener(new AbsListView.OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { } });
这样就可以得到listView滑动时的一些信息了,比如:第二个回调函数onScroll(),只要ListView处于滑动状态,就会被不断调用,这个函数方有三个参数,重点是第二个参数:firstVisibleItem, 该参数记录了该ListView当前第一个可视的列表项是第几个,所以根据这个参数就得知某个列表项是否可视,所以搜索框布局成为ListView的列表项后,就能知道搜索框是否被屏幕顶部遮住,假设搜索框布局的位置为position,那么可能的情况是:
1.如果firstVisibleItem < position,,则搜索框布局没有被遮住;
2.如果firstVisibleItem >= position,,则搜索框布局即将或者已经被布局顶部遮住,这时就要把替代布局显示出来,
所以大概的实现原理就是这样:
让搜索框布局成为ListView的列表项,实时监测搜索框布局的位置,并在其将被遮挡的时候显示出替代布局。
下面看看代码吧:
首先看布局文件:
//first_layout.xml,用于显示顶部的图片而已
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:gravity="center" android:layout_height="128dp"><ImageView android:layout_width="fill_parent" android:layout_height="164dp" android:scaleType="fitXY" android:src="@drawable/pic" /></LinearLayout>
//second_layout.xml,需要悬停在布局顶部的布局,很简单
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/secondLayout" android:alpha="100" android:padding="8dp" android:background="#ccddcc" > <SearchView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="secondLaout" android:textSize="48sp" android:textColor="#ffffff" android:layout_weight="1" android:background="@android:color/white" /> <Button style="@style/Widget.AppCompat.Button.Borderless.Colored" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="搜索" /></LinearLayout>
//activity_main.xml,主布局
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <ListView android:id="@+id/listView" android:layout_width="fill_parent" android:layout_height="fill_parent"/> <!--隐藏在布局顶部的视图--> <include layout="@layout/second_layout" android:visibility="gone" /></RelativeLayout>
布局文件都是很简单的,重点还是实现该功能的代码:
//MainActivity.java
public class MainActivity extends AppCompatActivity implements AbsListView.OnScrollListener{ ListView listView;//滑动列表控件 List<Person> lit; //列表数据集,不是重点 DataAdapter adapter;// /** * 第一个headerView,显示顶部图片的视图 */ View firstLayout; /** * 第二个HeaderView,下拉时需要悬停在顶部的View * 实际上该View在ListView向下滑动的那个时依旧会滑出界面, * 此时,需要一个相同的view及时出现在屏幕顶部,替代之。 */ View secondLaout; /** * 替代布局: *该View和secondLaout引用了同一个布局文件,所以二者会生成相同的view, * hideView会隐藏在屏幕顶部,等到secondLaout正好触碰到屏幕顶部时, * hideView就要及时出现,顶替secondLaout,以达到secondLaout好像悬停在屏幕顶部的效果。 */ View hideView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); firstLayout = LayoutInflater.from(this).inflate(R.layout.first_layout,null); secondLaout = LayoutInflater.from(this).inflate(R.layout.second_layout, null); hideView = findViewById(R.id.secondLayout); lit = new ArrayList<>(30); for(int i=0;i<30;i++) { lit.add(new Person("李白",25,"男")); } adapter = new DataAdapter(this,lit); listView = (ListView)findViewById(R.id.listView); //按顺序添加两个view,先添加的在上面。 listView.addHeaderView(firstLayout); listView.addHeaderView(secondLaout); listView.setAdapter(adapter); //listView监听滑动事件,很重要,因为可以根据滑动的位置 //决定是否要加载隐藏的视图hideView listView.setOnScrollListener(this); } @Override public void onScrollStateChanged(AbsListView view, int scrollState) { } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { /** * 核心代码: * 在滑动的那个过程中,判断如果第一个可见的列表项的位置(firstVisibleItem), * 如果是firstVisibleItem大于等于第二个,也就是说: * firstLayout已经滑出了屏幕,第一个可视的列表项是secondLaout或者是其后面的列表项, * 即接下来会滑出或已经滑出屏幕的列表项是secondLaout,换句话说: * secondLaout即将被挡住或者已经被挡住 * 此时要把hideView给显示出来,替代secondLaout. */ if(firstVisibleItem >= 1) { hideView.setVisibility(View.VISIBLE); } else //说明secondLaout没有被屏幕挡住,那就把hideView给收起来。 { hideView.setVisibility(View.INVISIBLE); } }}
代码及注释如上,是不是很简单呢,哈哈!
源码我放在github上了:
点我!
其实在尝试这个方案前,笔者和队友前前后后试了4,5中方案,效果都不尽人意,而这个点子,我也是了解到ListView.addHeaderView(View v)方法后才想到的,所以说,基础知识很重要啊!!功夫不负有心人。最后弄出来的时候,终于很安心地跑去睡觉了!!
PS,关于这个ListView.addHeaderView(View v)方法,根据其源码的注释,我发现了一些不同:以前addHeaderView(View v)方法要在setAdapter()方法调用前调用,否则会出错,但从Android 4.4开始,就没有这个限制了,这的确是个相当不错的改进啊!
PPS:笔者在实现这个功能后,才发现对于这种“顶部悬停”的效果,谷歌官方也是有做支持的!!详情请搜索Android Design Support Library这个强大的库。
- 利用ListView实现最简单的上滑悬停 (附源码)
- ListView简单实现分页加载(附源码)
- ListView简单实现分页加载(附源码)
- 最简单的鼠标悬停,实现下拉列表功能 bootstrap
- 最简单的listview实现
- Android UI开发: 横向ListView(HorizontalListView)及一个简单相册的完整实现 (附源码下载)
- Android UI开发: 横向ListView(HorizontalListView)及一个简单相册的完整实现 (附源码下载)
- Android UI开发: 横向ListView(HorizontalListView)及一个简单相册的完整实现 (附源码下载)
- Android UI开发: 横向ListView(HorizontalListView)及一个简单相册的完整实现 (附源码下载)
- Android:横向ListView(HorizontalListView)及一个简单相册的完整实现 (附源码下载)
- Android UI开发: 横向ListView(HorizontalListView)及一个简单相册的完整实现 (附源码下载)
- Android UI开发: 横向ListView(HorizontalListView)及一个简单相册的完整实现 (附源码下载)
- Android UI开发: 横向ListView(HorizontalListView)及一个简单相册的完整实现 (附源码下载)
- Android UI开发: 横向ListView(HorizontalListView)及一个简单相册的完整实现 (附源码下载)
- Android UI开发: 横向ListView(HorizontalListView)及一个简单相册的完整实现 (附源码下载)
- Android UI开发: 横向ListView(HorizontalListView)及一个简单相册的完整实现 (附源码下载)
- Android UI开发: 横向ListView(HorizontalListView)及一个简单相册的完整实现 (附源码下载)
- Android UI开发: 横向ListView(HorizontalListView)及一个简单相册的完整实现 (附源码下载)
- 使用spring @Scheduled注解执行定时任务
- sizeof
- javac compile java project and run
- Android UDP通信
- C语言实现的百分比加进度条的显示程序
- 利用ListView实现最简单的上滑悬停 (附源码)
- xen用FTP方式安装虚拟机系统
- 反射机制
- windows上caffe的编译
- Centos 6.4 python 2.6 升级到 2.7
- POJ 2051(最小堆/优先队列)
- C语言指针和文件笔记
- Android L APP 如何获取sys file system 中节点的写权限
- ImageButton 通过点击图像,完成提交的信息