最近做项目遇到一个需求,要做一个带有悬浮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. “VT-x is not available. (VERR_VMX_NO_VMX)” in VirtualBox

    Sometimes you can get “VT-x is not available. (VERR_VMX_NO_VMX)” error if you are trying to start x6 ...

  2. Linux VPS禁止某个IP访问

    http://www.vpser.net/security/linux-vps-deny-ip.html

  3. k-means算法Java一维实现

    这里的程序稍微有点变形.k_means方法返回K-means聚类的若干中心点.代码: import java.util.ArrayList; import java.util.Collections; ...

  4. C/S模式与B/S模式的详细介绍

    网络程序开发的两种计算模式--C/S模式与B/S模式.两种各有千秋,用于不同场合. C/S适用于专人使用,安全性要求较高的系统: B/S适用于交互性比较频繁的场合,容易被人们所接受,倍受用户和软件开发 ...

  5. java bean 合并

    package com.hainabo.mgcmall.util; import java.beans.BeanInfo;import java.beans.Introspector;import j ...

  6. mysql命令之二:查看mysql版本的四种方法

    1:在终端下:mysql -V. 以下是代码片段: [shengting@login ~]$ mysql -V mysql Ver 14.7 Distrib 4.1.10a, for redhat-l ...

  7. Springboot监控之一:SpringBoot四大神器之Actuator之2--springboot健康检查

    Health 信息是从 ApplicationContext 中所有的 HealthIndicator 的 Bean 中收集的, Spring Boot 内置了一些 HealthIndicator. ...

  8. ActiveMQ之一--ActiveMQ入门

    MQ的消费-生产者模型的一个典型的代表,一端往消息队列中不断的写入消息,而另一端则可以读取或者订阅队列中的消息.MQ和JMS类似,但不同的是JMS是SUN JAVA消息中间件服务的一个标准和API定义 ...

  9. 阻塞队列之一:BlockingQueue汇总

    一.阻塞队列介绍 BlockingQueue 通常用于一个线程生产对象,而另外一个线程消费这些对象的场景.下图是对这个原理的阐述: 一个线程往里边放,另外一个线程从里边取的一个 BlockingQue ...

  10. 操作系统-服务器-百科:Windows Server

    ylbtech-操作系统-服务器-百科:Windows Server Windows Server是微软在2003年4月24日推出的Windows 的服务器操作系统,其核心是Microsoft Win ...