最近做项目遇到一个需求,要做一个带有悬浮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的更多相关文章

  1. Android自定义组件系列【7】——进阶实践(4)

    上一篇<Android自定义组件系列[6]--进阶实践(3)>中补充了关于Android中事件分发的过程知识,这一篇我们接着来分析任老师的<可下拉的PinnedHeaderExpan ...

  2. Android自定义组件之自动换行及宽度自适应View:WordWrapView

    目的: 自定义一个ViewGroup,里面的子view都是TextView,每个子view  TextView的宽度随内容自适应且每行的子View的个数自适应,并可以自动换行 一:效果图 二:代码 整 ...

  3. Android自定义组件系列【6】——进阶实践(3)

    上一篇<Android自定义组件系列[5]--进阶实践(2)>继续对任老师的<可下拉的PinnedHeaderExpandableListView的实现>进行了分析,这一篇计划 ...

  4. Android自定义组件系列【5】——进阶实践(2)

    上一篇<Android自定义组件系列[5]--进阶实践(1)>中对任老师的<可下拉的PinnedHeaderExpandableListView的实现>前一部分进行了实现,这一 ...

  5. Android自定义组件系列【4】——自定义ViewGroup实现双侧滑动

    在上一篇文章<Android自定义组件系列[3]--自定义ViewGroup实现侧滑>中实现了仿Facebook和人人网的侧滑效果,这一篇我们将接着上一篇来实现双面滑动的效果. 1.布局示 ...

  6. Android自定义组件

    [参考的原文地址] http://blog.csdn.net/l1028386804/article/details/47101387效果图: 实现方式: 一:自定义一个含有EditText和Butt ...

  7. Android 自定义组件之如何实现自定义组件

    参考链接:http://blog.csdn.net/jjwwmlp456/article/details/41076699 简介 Android提供了用于构建UI的强大的组件模型.两个基类:View和 ...

  8. Android自定义组件系列【3】——自定义ViewGroup实现侧滑

    有关自定义ViewGroup的文章已经很多了,我为什么写这篇文章,对于初学者或者对自定义组件比较生疏的朋友虽然可以拿来主义的用了,但是要一步一步的实现和了解其中的过程和原理才能真真脱离别人的代码,举一 ...

  9. Android 自定义组件,自定义LinearLayout,ListView等样式的组件

    今天讲的其实以前自己用过,就是在网上拿下来的把图片裁剪成圆形的方法,之前的随笔也介绍过的, 用法就是,在布局里写控件或者组件的时候得把从com开始到你写的那个类的所有路径写下来. 至于我们该怎么创建呢 ...

随机推荐

  1. 在Eclipse中导入dtd和xsd文件,使XML自动提示

    DTD 类型约束文件    1. Window->Preferences->XML->XML Catalog->User Specified Entries窗口中,选择Add ...

  2. 自定义vue全局组件use使用(解释vue.use()的原理)

    我们在前面学习到是用别人的组件:Vue.use(VueRouter).Vue.use(Mint)等等.其实使用的这些都是全剧组件,这里我们就来讲解一下怎么样定义一个全局组件,并解释vue.use()的 ...

  3. Google、IBM和Lyft开源其大型微服务系统管理工具Istio

    Istio 的优势 集群规模可视性:在故障状况出现时,运营人员需要利用多种工具以始终关注集群运行状况并分析微服务状态图表.Istio 项目能够监控与应用程序及网络活动相关的数据,利用 Promethe ...

  4. 本地tomcat调用远程接口报错:java.lang.reflect.InvocationTargetException

    今天碰到一个奇怪的问题,本地Eclipse起了一个tomcat通过http去调一个外部接口,结果竟然报了一个反射的异常,先看下完整日志: , :: 下午 org.apache.catalina.sta ...

  5. adb error: device offline

    adb 调试一直报错 $ adb shell error: device offline 解决办法: $ adb kill-server $ adb start-server * daemon not ...

  6. NFS搭建与配置

    NFS应用场景是:A,B,C三台机器上需要保证被访问到的文件是一样的,A共享数据出来,B和C分别去挂载A共享的数据目录,从而B和C访问到的数据和A上的一致性 172.131.1.135  服务器端 1 ...

  7. "==" 与 “equals”

    “==”: “==”或等号操作在Java编程语言中是一个二元操作符,用于比较原生类型和对象.(操作符不支持重载overloading) “==”对比两个对象基于内存引用,如果两个对象的引用完全相同(指 ...

  8. Django 的ORM

    指定字段: <1> CharField:字符串字段,用于较短的字符串,CharField 要求必须有一个参数 maxlength,用于从数据库层和Django效验层限制该字段所允许的最大字 ...

  9. centos7 桥接配置

    cd /etc/sysconfig/network-scripts/ 名字可能各不同,一般出现在第一个位置 vim ifcfg-ens33 然后重启 systemctl restart network ...

  10. 十七.jQuery源码解析之入口方法Sizzle(1)

    函数Sizzle(selector,context,results,seed)用于查找与选择器表达式selector匹配的元素集合.该函数是选择器引擎的入口. 函数Sizzle执行的6个关键步骤如下: ...