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开始到你写的那个类的所有路径写下来. 至于我们该怎么创建呢 ...
随机推荐
- ffmpeg && nginx hls
备注: 使用ffmpeg 将视频转换为hls,并使用nginx 提供服务,实现点播功能,没有使用rtmp 插件 1. ffmpeg 命令生成文件 a. ts ffmpeg -y -i mydemo. ...
- modsecurity3.0 nginx 安装
备注: 使用的是modsecurity 3.0 的版本,也是nginx 官方推荐使用的,同时使用的是nginx 的dynamic module 1. 环境准备 https://github.com/S ...
- Toxiproxy 网络情况模式代理
1. 介绍 Toxiproxy is a framework for simulating network conditions. It's made specifically to work in ...
- VirtulBox安装虚拟机(鼠标点击时)0x00000000指令引用的0x00000000内存该内存不能为written错误解决方案
这个错误并不是所有人都会用到,我用的是WIN7系统,公司的电脑.查找了很多原因后,发现的确是由于系统主题被破解过的原因. 手工恢复风险太高.通过下面的工具就可以直接恢复.UniversalThemeP ...
- gitlab安装、配置与阿里云产品集成
https://www.ilanni.com/?p=12819 一.gitlab安装与部署 gitlab的安装可以分为源码安装和通过安装包进行安装,要是按照我以前的写作习惯的话,我也会把源码安装在本文 ...
- Qt学习之秒表的实现(StopWatch) (转)
秒表对于我来说并不陌生,在之前自己学习单片机时,实现过秒表和数字钟:基本思路:开启单片机带的定时器,并设置它没10ms溢出一次,分别用三个变量hour,minute,secong记录秒表的时分秒,然后 ...
- 配置Jar包及相关依赖Jar包的本地存放路径
配置Jar包及相关依赖Jar包的本地存放路径 用 maven2 ,pom.xml中设置了依赖,会帮你下载所有依赖的.jar到 M2_REPO 指向的目录. M2_REPO是一个用来定义 maven 2 ...
- laravel的auth用户认证的例子
参考http://www.cnblogs.com/yjf512/p/4042356.html 需要注意的是,生成的测试数据,password部分必须用laravel自带的hash一下 Hash::ma ...
- android 网络连接判断
Android 网络判断类,用来判断网络状态 使用方法: (1)先初始化 //初始化网络状态检测类 NetworkStateManager.instance().init(this); (2)判断是否 ...
- java web 程序---登陆验证注销/重定向session_login.jsp/
思路:第一个页面是:session_login.页面,一个form表单,一个脚本,输入的名称不为空,不,则重定向 到welcome.jsp页面.否则,显示登陆失败,请输入登陆名称: 第二个页面,是we ...