900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > Android 自定义listview的下拉刷新

Android 自定义listview的下拉刷新

时间:2020-07-22 14:20:13

相关推荐

Android 自定义listview的下拉刷新

现在的listview的下拉刷新各种各样,今天就来给大家提供一个比较简单的下拉刷新,自己动手敲吧。

大概的功能就是:listview下拉的时候提示下拉可以刷新,到一定的距离后提示松开可以刷新(旋转下拉箭头),手指离开屏幕后正在刷新...将提示箭头变成圆形进度条。

listview的下拉刷新的大概的几个步骤:

1、添加listview的头部界面 headerView;

2、监听listview的滚动事件 OnScrollListener();

3、监听listview的触摸事件 onTouch();

4、加载最新数据;

第一步 创建listview的头部布局 header

1、布局中包括了提示语的控件TextView,时间的Textview、有一个提示的图标ImageView、还有一个进度条ProgressBar默认不显示的。

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="/apk/res/android"

android:layout_width="match_parent"

android:layout_height="match_parent">

<RelativeLayout

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:paddingBottom="10dp"

android:paddingTop="10dp">

<LinearLayout

android:id="@+id/layout"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_centerInParent="true"

android:gravity="center"

android:orientation="vertical">

<TextView

android:id="@+id/tip"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="下拉可以刷新!" />

<TextView

android:id="@+id/lastupdate_time"

android:layout_width="wrap_content"

android:layout_height="wrap_content" />

</LinearLayout>

<ImageView

android:id="@+id/arrow"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginRight="20dp"

android:layout_toLeftOf="@id/layout"

android:src="@mipmap/pull_to_refresh_arrow" />

<ProgressBar

android:id="@+id/progress"

style="@style/Base.TextAppearance.AppCompat.Small"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginRight="20dp"

android:layout_toLeftOf="@id/layout"

android:visibility="gone" />

</RelativeLayout>

</LinearLayout>

2、创建好布局后将其添加在listview的头部

1> 继承listview,实现OnScrollListener的接口重写onScrollStateChanged()、onScroll()。

2> 在构造方法里添加布局文件headerView

LayoutInflater inflater = LayoutInflater.from(context);

header = inflater.inflate(R.layout.header_layout, null);

//添加头部的view

this.addHeaderView(header);

3> 头部的布局默认应该是隐藏的;实现的思路就是可以将头部布局的上边距设置成header高度的负值。

1.首先要得到header 的高度

/**

* 获取子控件高度和宽度

*

* @param view

*/

private void meadsureView(View view) {

ViewGroup.LayoutParams p = view.getLayoutParams();

if (p == null) {

p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);

}

int width = ViewGroup.getChildMeasureSpec(0, 0, p.width);

int height;

int tempHeight = p.height;

if (tempHeight > 0) {

height = MeasureSpec.makeMeasureSpec(tempHeight, MeasureSpec.EXACTLY);

} else {

height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);

}

view.measure(width, height);

}

2.设置header的上边距,上边距的值应该为header的负值。

/**

* 设置header布局的上边距

*

* @param topPadding

*/

private void topPadding(int topPadding) {

header.setPadding(header.getPaddingLeft(), topPadding, header.getPaddingRight(), header.getPaddingBottom());

header.invalidate();

}

3.初始化header

/**

* 初始化界面,添加顶部布局文件到listview

*

* @param context

*/

private void initView(Context context) {

LayoutInflater inflater = LayoutInflater.from(context);

header = inflater.inflate(R.layout.header_layout, null);

meadsureView(header);

headerHeight = header.getMeasuredHeight();

topPadding(-headerHeight);

//添加头部的view

this.addHeaderView(header);

this.setOnScrollListener(this);

}

通过以上三步我们就可以成功就header隐藏掉。

第二步 监听listview的滚动事件

1、初始记得设置OnScrollListener的监听事件this.setOnScrollListener(this);

2、重写下面两个方法

@Override

public void onScrollStateChanged(AbsListView absListView, int scrollState) {

this.scrollState = scrollState;

}

@Override

public void onScroll(AbsListView absListView, int firsVisibleItem, int visibleItemCount, int totalItemCount) {

//firsVisibleItem是否是第一条也就意味着是否在listview的最顶端从而判断header的显示隐藏以及之后的刷新等等

this.firsVisibleItem = firsVisibleItem;

}

3、监听用户的(onTouchEvent())手势判断是按下、移动、抬起...

1> //isRemark标记的是否在当前的listview的顶端按下的

//startY是按下时的Y值

//state当前操作的状态

@Override

public boolean onTouchEvent(MotionEvent ev) {

switch (ev.getAction()) {

case MotionEvent.ACTION_DOWN:

if (firsVisibleItem == 0) {

isRemark = true;

startY = (int) ev.getY();

}

break;

case MotionEvent.ACTION_MOVE:

onMove(ev);

break;

case MotionEvent.ACTION_UP:

if (state == RELESE) {

state = REFLAHING;

//添加数据

reflashViewByState();

iReflashLisener.onReflash();

} else if (state == PULL) {

state = NONE;

isRemark = false;

reflashViewByState();

}

break;

}

return super.onTouchEvent(ev);

}

2>根据移动的距离判断在移动过程的状态。正常、下拉、松开、刷新四个状态。

//space是移动的距离

状态判断

space > 0 正常转下拉状态 (ps:下拉可以刷新)

space > headerHeight+30&&scrollState == SCROLL_STATE_TOUCH_SCROLL 下拉转松开状态 (ps:松开可以刷新)

space < headerHeight+30 松开转下拉状态 (ps:下拉可以刷新)

space <= 0 下拉转正常状态 (ps:header隐藏)

/**

* 判断listview在移动过程中的操作

*

* @param ev

*/

private void onMove(MotionEvent ev) {

if (!isRemark) {

return;

}

int tempY = (int) ev.getY();

int space = tempY - startY;

int topPadding = space - headerHeight;

switch (state) {

case NONE:

if (space > 0) {

state = PULL;

reflashViewByState();

}

break;

case PULL:

topPadding(topPadding);

if (space > headerHeight + 30 && scrollState == SCROLL_STATE_TOUCH_SCROLL) {

state = RELESE;

reflashViewByState();

}

break;

case RELESE:

topPadding(topPadding);

if (space < headerHeight + 30) {

state = PULL;

reflashViewByState();

} else if (space <= 0) {

state = NONE;

isRemark = false;

reflashViewByState();

}

break;

}

}

3>根据当前的操作状态(正常、下拉、松开、刷新)判断header的显示内容:

/**

* 判断当前状态更改header的布局

*/

private void reflashViewByState() {

TextView tip = (TextView) header.findViewById(R.id.tip);

ImageView arrow = (ImageView) header.findViewById(R.id.arrow);

ProgressBar progressBar = (ProgressBar) header.findViewById(R.id.progress);

RotateAnimation anim = new RotateAnimation(0, 180,

RotateAnimation.RELATIVE_TO_SELF, 0.5f,

RotateAnimation.RELATIVE_TO_SELF, 0.5f);

anim.setDuration(500);

anim.setFillAfter(true);

RotateAnimation anim1 = new RotateAnimation(180, 0,

RotateAnimation.RELATIVE_TO_SELF, 0.5f,

RotateAnimation.RELATIVE_TO_SELF, 0.5f);

anim1.setDuration(500);

anim1.setFillAfter(true);

switch (state) {

case NONE:

arrow.clearAnimation();

topPadding(-headerHeight);

break;

case PULL:

arrow.setVisibility(View.VISIBLE);

progressBar.setVisibility(View.GONE);

tip.setText("下拉可以刷新!");

arrow.clearAnimation();

arrow.setAnimation(anim1);

break;

case RELESE:

arrow.setVisibility(View.VISIBLE);

progressBar.setVisibility(View.GONE);

tip.setText("松开可以刷新!");

arrow.clearAnimation();

arrow.setAnimation(anim);

break;

case REFLAHING:

topPadding(50);

arrow.setVisibility(View.GONE);

progressBar.setVisibility(View.VISIBLE);

tip.setText("正在刷新...");

arrow.clearAnimation();

break;

}

}

4、为刷新数据提供一个接口,然后通过activity实现重现onReflash()方法。

/**

* 刷新数据接口

*/

public interface IReflashLisener {

void onReflash();

}

activity调用的结果:

@Override

public void onReflash() {

Handler handler = new Handler();

handler.postDelayed(new Runnable() {

@Override

public void run() {

//后台请求数据

addReflashData();

//通知界面

myAdapter.notifyDataSetChanged();

Toast.makeText(MainActivity.this, "刷新成功", Toast.LENGTH_SHORT).show();

mList.reflashComplete();

}

}, 2000);

}

下面是源码:

package com.nz.zdd.zlistview.widget;

import android.content.Context;

import android.util.AttributeSet;

import android.util.Log;

import android.view.LayoutInflater;

import android.view.MotionEvent;

import android.view.View;

import android.view.ViewGroup;

import android.view.animation.RotateAnimation;

import android.widget.AbsListView;

import android.widget.AbsListView.OnScrollListener;

import android.widget.ImageView;

import android.widget.ListView;

import android.widget.ProgressBar;

import android.widget.TextView;

import com.nz.zdd.zlistview.R;

import java.text.SimpleDateFormat;

import java.util.Date;

/**

* Created by zdd on /9/8.

*/

public class ZReFlashListView extends ListView implements OnScrollListener {

/**

* 顶部布局文件

*/

private View header;

/**

* 顶部布局文件的高度

*/

private int headerHeight;

/**

* 当前item的位置

*/

private int firsVisibleItem;

/**

* 判断是否是listview最顶端按下的

*/

public boolean isRemark;

/**

* 记录按下的Y值

*/

private int startY;

/**

* 当前状态

*/

private int state;

/**

* 正常状态

*/

private final int NONE = 0;

/**

* 提示下拉状态

*/

private final int PULL = 1;

/**

* 松开提示状态

*/

private final int RELESE = 2;

/**

* 正在刷新状态

*/

private final int REFLAHING = 3;

/**

* lsitview当前滚动状态

*/

private int scrollState;

public IReflashLisener iReflashLisener;

public void setInterface(IReflashLisener iReflashLisener) {

this.iReflashLisener = iReflashLisener;

}

public ZReFlashListView(Context context) {

super(context);

initView(context);

}

public ZReFlashListView(Context context, AttributeSet attrs) {

super(context, attrs);

initView(context);

}

public ZReFlashListView(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

initView(context);

}

/**

* 初始化界面,添加顶部布局文件到listview

*

* @param context

*/

private void initView(Context context) {

LayoutInflater inflater = LayoutInflater.from(context);

header = inflater.inflate(R.layout.header_layout, null);

meadsureView(header);

headerHeight = header.getMeasuredHeight();

topPadding(-headerHeight);

//添加头部的view

this.addHeaderView(header);

this.setOnScrollListener(this);

}

/**

* 获取子控件高度和宽度

*

* @param view

*/

private void meadsureView(View view) {

ViewGroup.LayoutParams p = view.getLayoutParams();

if (p == null) {

p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);

}

int width = ViewGroup.getChildMeasureSpec(0, 0, p.width);

int height;

int tempHeight = p.height;

if (tempHeight > 0) {

height = MeasureSpec.makeMeasureSpec(tempHeight, MeasureSpec.EXACTLY);

} else {

height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);

}

view.measure(width, height);

}

/**

* 设置header布局的上边距

*

* @param topPadding

*/

private void topPadding(int topPadding) {

header.setPadding(header.getPaddingLeft(), topPadding, header.getPaddingRight(), header.getPaddingBottom());

header.invalidate();

}

@Override

public boolean onTouchEvent(MotionEvent ev) {

switch (ev.getAction()) {

case MotionEvent.ACTION_DOWN:

if (firsVisibleItem == 0) {

isRemark = true;

startY = (int) ev.getY();

}

break;

case MotionEvent.ACTION_MOVE:

onMove(ev);

break;

case MotionEvent.ACTION_UP:

if (state == RELESE) {

state = REFLAHING;

//添加数据

reflashViewByState();

iReflashLisener.onReflash();

} else if (state == PULL) {

state = NONE;

isRemark = false;

reflashViewByState();

}

break;

}

return super.onTouchEvent(ev);

}

/**

* 判断listview在移动过程中的操作

*

* @param ev

*/

private void onMove(MotionEvent ev) {

if (!isRemark) {

return;

}

int tempY = (int) ev.getY();

int space = tempY - startY;

int topPadding = space - headerHeight;

switch (state) {

case NONE:

if (space > 0) {

state = PULL;

reflashViewByState();

}

break;

case PULL:

topPadding(topPadding);

if (space > headerHeight + 30 && scrollState == SCROLL_STATE_TOUCH_SCROLL) {

state = RELESE;

reflashViewByState();

}

break;

case RELESE:

topPadding(topPadding);

if (space < headerHeight + 30) {

state = PULL;

reflashViewByState();

} else if (space <= 0) {

state = NONE;

isRemark = false;

reflashViewByState();

}

break;

}

}

/**

* 判断当前状态更改header的布局

*/

private void reflashViewByState() {

TextView tip = (TextView) header.findViewById(R.id.tip);

ImageView arrow = (ImageView) header.findViewById(R.id.arrow);

ProgressBar progressBar = (ProgressBar) header.findViewById(R.id.progress);

RotateAnimation anim = new RotateAnimation(0, 180,

RotateAnimation.RELATIVE_TO_SELF, 0.5f,

RotateAnimation.RELATIVE_TO_SELF, 0.5f);

anim.setDuration(500);

anim.setFillAfter(true);

RotateAnimation anim1 = new RotateAnimation(180, 0,

RotateAnimation.RELATIVE_TO_SELF, 0.5f,

RotateAnimation.RELATIVE_TO_SELF, 0.5f);

anim1.setDuration(500);

anim1.setFillAfter(true);

switch (state) {

case NONE:

arrow.clearAnimation();

topPadding(-headerHeight);

break;

case PULL:

arrow.setVisibility(View.VISIBLE);

progressBar.setVisibility(View.GONE);

tip.setText("下拉可以刷新!");

arrow.clearAnimation();

arrow.setAnimation(anim1);

break;

case RELESE:

arrow.setVisibility(View.VISIBLE);

progressBar.setVisibility(View.GONE);

tip.setText("松开可以刷新!");

arrow.clearAnimation();

arrow.setAnimation(anim);

break;

case REFLAHING:

topPadding(50);

arrow.setVisibility(View.GONE);

progressBar.setVisibility(View.VISIBLE);

tip.setText("正在刷新...");

arrow.clearAnimation();

break;

}

}

/**

* 获取成功后

*/

public void reflashComplete() {

state = NONE;

isRemark = false;

reflashViewByState();

SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss");

Date date = new Date(System.currentTimeMillis());

String time = simpleDateFormat.format(date);

TextView lastupdate_time = (TextView) header.findViewById(R.id.lastupdate_time);

lastupdate_time.setText(time);

}

@Override

public void onScrollStateChanged(AbsListView absListView, int scrollState) {

this.scrollState = scrollState;

}

@Override

public void onScroll(AbsListView absListView, int firsVisibleItem, int visibleItemCount, int totalItemCount) {

this.firsVisibleItem = firsVisibleItem;

}

/**

* 刷新数据接口

*/

public interface IReflashLisener {

void onReflash();

}

}

MainActivity中调用:

package com.nz.zdd.zlistview;

import android.app.Activity;

import android.os.Handler;

import android.support.v7.app.AppCompatActivity;

import android.os.Bundle;

import android.widget.ListView;

import android.widget.Toast;

import com.nz.zdd.zlistview.adapter.MyAdapter;

import com.nz.zdd.zlistview.entity.Person;

import com.nz.zdd.zlistview.widget.ZReFlashListView;

import java.util.ArrayList;

import java.util.List;

public class MainActivity extends Activity implements ZReFlashListView.IReflashLisener {

private ZReFlashListView mList;

private Person mPerson;

private MyAdapter myAdapter;

private List<Person> mListData = new ArrayList<>();

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

addData();

initView();

}

private void initView() {

mList = (ZReFlashListView) findViewById(R.id.listData);

mList.setInterface(this);

myAdapter = new MyAdapter(mListData, MainActivity.this);

mList.setAdapter(myAdapter);

myAdapter.notifyDataSetChanged();

}

private void addData() {

for (int i = 0; i < 20; i++) {

mPerson = new Person();

mPerson.setName("张三");

mPerson.setSex("男");

mPerson.setAge(i);

mListData.add(mPerson);

}

}

@Override

public void onReflash() {

Handler handler = new Handler();

handler.postDelayed(new Runnable() {

@Override

public void run() {

//后台请求数据

addReflashData();

//通知界面

myAdapter.notifyDataSetChanged();

Toast.makeText(MainActivity.this, "刷新成功", Toast.LENGTH_SHORT).show();

mList.reflashComplete();

}

}, 2000);

}

private void addReflashData() {

for (int i = 0; i < 5; i++) {

mPerson = new Person();

mPerson.setName("李四");

mPerson.setSex("女");

mPerson.setAge(i);

mListData.add(0,mPerson);

}

}

}

好了基本上的功能都已经实现了,如果有喜欢的可以试试。。讲的不对的地方看看代码。欢迎留言。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。