Android 自定义组件之 带有悬浮header的listview
最近做项目遇到一个需求,要做一个带有悬浮header的listview,即,当listview滑动时,header消失,静止时header浮现。
这个需求看似简单,实际做起来还是会遇到不少的困难,特此记录过程,以做记录。
首先,我们来看看需求,如下图。

有了需求,我们就可以开始做具体分析了,首先我们想到的是给listview添加一个滑动监听,在滑动时隐藏header在静止的时候就显示header。
关键代码如下:
list.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if(AbsListView.OnScrollListener.SCROLL_STATE_IDLE == scrollState){
play(false,y);
}
if(AbsListView.OnScrollListener.SCROLL_STATE_FLING == scrollState){
play(true,y);
}
if(AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL == scrollState) {
}
}
其中play()就是我们的隐藏/显示 header的方法啦
写好了监听之后我们开始写隐藏/显示的PLAY()方法
首先我们来写一个简单的版本
private void play(boolean x,boolean y)
{
Animation animation;
if(x){
animation = new AlphaAnimation(1,0);
animation.setDuration(1000);
textview.startAnimation(animation);
textview.setVisibility(View.GONE);
/* if(!y){
list.setPadding(0,0,0,0);
deal();
}*/
}
else{
textview.setVisibility(View.VISIBLE);
animation = new AlphaAnimation(0,1);
animation.setDuration(2000);
textview.startAnimation(animation);
View view = new View(this);
}
}
可以看到我们通过第一个布尔参数来判断是隐藏还是显示。
做到这里看似已经完成了,但是有更多的细节是需要打磨的,由于我们采用的FrameLayout进行布局,当我们在顶部的时候会发现第一条记录被挡住了,这可不行。
不过我们可以通过设置listview的padding还解决,代码如下。
int i = textview.getLayoutParams().height;
list.setPadding(0,i,0,0);
现在运行我们的程序,好像已经完成了,但是这个时候可恶的BUG又出来捣乱了。
当我们只有少量记录(比屏幕显示多一条)的时候,会出现padding设置了之后无法还原的情况,这是因为虽然第一条记录被隐藏了一部分,但是并不是完全隐藏,所以不会触发listview的top事件。
这时候我们就需要在每次滑动的时候去检测滑动的距离,来判断是不是需要设置padding了,如果第一条记录都没有被隐藏,那么显然我们是不需要设置padding的。
private void deal()
{
View c = list.getChildAt(0);
int first = list.getFirstVisiblePosition();
int top = c.getTop();
int hight = c.getHeight();
int distance = first*hight - top;
if(distance < hight)
{
int i = textview.getLayoutParams().height;
list.setPadding(0,i,0,0);
} }
这就是判断滑动距离的函数啦。
至此,一个简单的悬浮header listview已经完成了。
接下来是完整的布局和代码
布局:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
tools:context=".MainActivity"> <TextView
android:id="@+id/txt"
android:gravity="center"
android:background="#000"
android:text="Hello World!"
android:textColor="#0cbdb7"
android:textSize="40sp"
android:layout_width="match_parent"
android:layout_height="50dp" />
<ListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent"/> </FrameLayout>
代码:
package com.example.administrator.listviewtest; import android.app.Activity;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.widget.AbsListView;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView; import java.util.ArrayList;
import java.util.List; public class MainActivity extends Activity {
TextView textview;
ListView list;
boolean y = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
list = (ListView)findViewById(R.id.listview);
textview = (TextView)findViewById(R.id.txt);
List<String> list1 = new ArrayList<>();
for(int i = 0;i < 100;i++)
{
list1.add("record"+(i+1));
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_expandable_list_item_1,list1);
list.setAdapter(adapter); list.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if(AbsListView.OnScrollListener.SCROLL_STATE_IDLE == scrollState){
play(false,y);
}
if(AbsListView.OnScrollListener.SCROLL_STATE_FLING == scrollState){
play(true,y);
}
if(AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL == scrollState) {
// play(true, y);
}
} @Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if(firstVisibleItem == 0)
{
Log.i("list","top");
y = true;
int i = textview.getLayoutParams().height;
list.setPadding(0,i,0,0);
}
else
{
y = false;
}
}
});
}
private void play(boolean x,boolean y)
{
Animation animation;
if(x){
animation = new AlphaAnimation(1,0);
animation.setDuration(1000);
textview.startAnimation(animation);
textview.setVisibility(View.GONE);
if(!y){
list.setPadding(0,0,0,0);
deal();
}
}
else{
textview.setVisibility(View.VISIBLE);
animation = new AlphaAnimation(0,1);
animation.setDuration(2000);
textview.startAnimation(animation);
View view = new View(this);
}
}
private void deal()
{
View c = list.getChildAt(0);
int first = list.getFirstVisiblePosition();
int top = c.getTop();
int hight = c.getHeight();
int distance = first*hight - top;
if(distance < hight)
{
int i = textview.getLayoutParams().height;
list.setPadding(0,i,0,0);
} }
}
Android 自定义组件之 带有悬浮header的listview的更多相关文章
- Android自定义组件系列【7】——进阶实践(4)
上一篇<Android自定义组件系列[6]--进阶实践(3)>中补充了关于Android中事件分发的过程知识,这一篇我们接着来分析任老师的<可下拉的PinnedHeaderExpan ...
- Android自定义组件之自动换行及宽度自适应View:WordWrapView
目的: 自定义一个ViewGroup,里面的子view都是TextView,每个子view TextView的宽度随内容自适应且每行的子View的个数自适应,并可以自动换行 一:效果图 二:代码 整 ...
- Android自定义组件系列【6】——进阶实践(3)
上一篇<Android自定义组件系列[5]--进阶实践(2)>继续对任老师的<可下拉的PinnedHeaderExpandableListView的实现>进行了分析,这一篇计划 ...
- Android自定义组件系列【5】——进阶实践(2)
上一篇<Android自定义组件系列[5]--进阶实践(1)>中对任老师的<可下拉的PinnedHeaderExpandableListView的实现>前一部分进行了实现,这一 ...
- Android自定义组件系列【4】——自定义ViewGroup实现双侧滑动
在上一篇文章<Android自定义组件系列[3]--自定义ViewGroup实现侧滑>中实现了仿Facebook和人人网的侧滑效果,这一篇我们将接着上一篇来实现双面滑动的效果. 1.布局示 ...
- Android自定义组件
[参考的原文地址] http://blog.csdn.net/l1028386804/article/details/47101387效果图: 实现方式: 一:自定义一个含有EditText和Butt ...
- Android 自定义组件之如何实现自定义组件
参考链接:http://blog.csdn.net/jjwwmlp456/article/details/41076699 简介 Android提供了用于构建UI的强大的组件模型.两个基类:View和 ...
- Android自定义组件系列【3】——自定义ViewGroup实现侧滑
有关自定义ViewGroup的文章已经很多了,我为什么写这篇文章,对于初学者或者对自定义组件比较生疏的朋友虽然可以拿来主义的用了,但是要一步一步的实现和了解其中的过程和原理才能真真脱离别人的代码,举一 ...
- Android 自定义组件,自定义LinearLayout,ListView等样式的组件
今天讲的其实以前自己用过,就是在网上拿下来的把图片裁剪成圆形的方法,之前的随笔也介绍过的, 用法就是,在布局里写控件或者组件的时候得把从com开始到你写的那个类的所有路径写下来. 至于我们该怎么创建呢 ...
随机推荐
- GCC用法
http://www.cnblogs.com/hibernate6/archive/2010/08/24/2522057.html
- Protel 99 铺铜的一个坑 Pour Over Same
Protel 99 铺铜的一个坑 Pour Over Same 好久没用 Protel 99 了,修改了一个旧的 PCB 文件. 需要修改线路,由于改了线路需要重新铺铜,得重新画铺铜的边框. 以下这个 ...
- FastAdmin 源码分析:jQuery 含逗号的选择器
FastAdmin 源码分析:jQuery 含逗号的选择器 在 FastAdmin 你常常会看到以下 jQuery 选择器的代码. if ($(".datetimepicker", ...
- 使用 Git 对原理图和线路板时行版本控制
使用 Git 对原理图和线路板时行版本控制 由于之前一直用 Git 管理代码,我又开始试用 git 来对原理图和线路板时行版本控制. 由于 原理图和 PCB 的文件都是二进制文件,git 管理并不怎么 ...
- js动态的属性名如何取该属性的值
var cls={cn1:"nihao",cn2="made",cn3="shuide"};var index=2;//可变获取cn2的值 ...
- mac系统PHP 7.1.12安装xhprof并使用[View Full Callgraph]小记
前几天从php7.0.x 升级到了php7.2.0版本, 结果装xhprof没有找到能支持对应版本的xhprof 于是又安装了一个php7.1.2的版本(brew install h) 接着安装xhp ...
- iso网络模型
tcp/ip知识 1.iOS七层模型 应用层 表示层 应用层 ssh httpssl tls ftp mime html snmp 会话层 传输层 传输层 tcp udp 网络层 网络层 ipv6 i ...
- phpstudy mysql无法启动
在安装好phpstudy后,Apache可以启动,Mysql无法启动. 以管理员的身份运行cmd,然后输入sc delete mysql 即可
- 分布式事务之:TCC几个框架的测试情况记录
国内主要的开源TCC分布式事务框架包括 框架名称 Github地址 star数量 tcc-transaction https://github.com/changmingxie/tcc-tran ...
- MySQL 5.7 坑爹参数 – log_timestamps
官网原话: This variable was added in MySQL 5.7.2. Before 5.7.2, timestamps in log messages were written ...