148.模拟下拉刷新

xiaoxiao2021-02-27  519

设置窗体的样式可以直接在Manifist文件中的style中直接设置 android:theme="@style/AppTheme",这是一个全局App的属性,也可以在activity中设置requestWindowFeature(Window.FEATURE_NO_TITLE);设置没有title的窗体样式。

下拉的时候出现了下拉刷新的字样,需要为拉出的部分单独设计样式

android:indeterminate="true"圆圈的进度条

style="@android:style/Widget.ProgressaBar"圆圈的进度条

style="@android:style/Widget.ProgressaBar.Horizontal"水平进度条

android:indeterminateDrawable="@drawable/indeterminate_drawable"设置自定义的圆圈,在res/drawable目录下创建indeterminate_drawable.xml的样式文件

刷新头部的填充方法如下,这个方法必须在setAdapter前面调用,也就是1.addHeaderView必须在setAdapter之前调用。2.将paddingTop设置一个headerView高度的负值去隐藏它

//初始化头部的填充 View headView = View.inflate(this, R.layout.layout_head, null); //添加刷新的布局,添加到自定义listView的顶部 refreshListView.addHeaderView(headView);getHeight()和getMeasuredHeight()的区别: getMeasuredHeight():获取测量完的高度,只要在onMeasure方法执行完,就可以用它获取到宽高,在自定义控件内部多使用这个使用view.measure(0,0)方法可以主动通知系统去测量,然后就可以直接使用它获取宽高 headView.measure(0, 0);//主动通知系统去测量 int headViewHeight = headView.getMeasuredHeight(); Log.e("MainActivity", "headViewHeight: "+headViewHeight); headView.setPadding(0, -headViewHeight, 0, 0); refreshListView.addHeaderView(headerView);getHeight():必须在onLayout方法执行完后,才能获得宽高 //初始化头部的填充 final View headView = View.inflate(this, R.layout.layout_head, null); //监听headView,xml文件是异步的,一开始没有获取到高度 headView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { //获取到headView高度来,设置隐藏的padding int headViewHeight = headView.getHeight(); //设置padding headView.setPadding(0, -headViewHeight, 0, 0); //添加刷新的布局,添加到自定义listView的顶部,必须在setAdapter前面调用 refreshListView.addHeaderView(headView); } });

下拉刷新通过添加接口来实现监听

//接口变量创建 private OnRefreshListener listener; public void setOnRefreshListener(OnRefreshListener listener){ this.listener = listener; } //创建接口 public interface OnRefreshListener{ void onPullRefresh(); void onLoadingMore(); }接口的使用 //监听refreshListView refreshListView.setOnRefreshListener(new OnRefreshListener(){ //松开进入刷新状态 @Override public void onPullRefresh() { System.out.println("松开状态进入刷新"); } @Override public void onLoadingMore() { // TODO Auto-generated method stub } });上拉刷新,上拉刷新不需要添加接口直接使用OnScrollListener继承这个接口就可以以了

使用的时候首先初始化滚动监听

//设置一个滚动监听器 setOnScrollListener(this);再实现接口方法 //滚动的接口方法,滚动状态的改变 @Override public void onScrollStateChanged(AbsListView view, int scrollState) { //SCROLL_STATE_IDLE闲置状态,手指松开的时候的状态 //SCROLL_STATE_TOUCH_SCROLL:手指触摸滑动,就是按着来滑动 //SCROLL_STATE_FLING:快速滑动后松开,惯性 if(scrollState==OnScrollListener.SCROLL_STATE_IDLE && getLastVisiblePosition()==(getCount()-1) &&!isLoadingMore){ isLoadingMore = true; footerView.setPadding(0, 0, 0, 0);//显示出footerView setSelection(getCount());//让listview最后一条显示出来 if(listener!=null){ listener.onLoadingMore(); } } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { // TODO Auto-generated method stub }使用setSelection(getCount());//让listview的某一条显示在顶端。让最下面的一条显示出来

主布局文件activity_main.xml,使用的自定义布局作为listView

<RelativeLayout 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" > <com.ldw.refresh.RefreshListView android:id="@+id/refreshListView" android:layout_width="match_parent" android:layout_height="wrap_content" ></com.ldw.refresh.RefreshListView> </RelativeLayout>layout_header.xml头部的布局 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_horizontal" android:orientation="horizontal" > <RelativeLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:layout_marginBottom="20dp" > <ImageView android:id="@+id/iv_arrow" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:background="@drawable/indicator_arrow" /> <ProgressBar android:id="@+id/pb_rotate" android:layout_width="40dp" android:layout_height="40dp" android:layout_centerInParent="true" android:indeterminate="true" android:indeterminateDuration="1000" android:indeterminateDrawable="@drawable/indeterminate_drawable" /> </RelativeLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" android:gravity="center" android:layout_marginLeft="20dp" android:layout_marginTop="20dp" android:layout_marginBottom="20dp" > <TextView android:id="@+id/tv_state" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="20sp" android:textColor="#aa000000" android:text="下拉刷新" /> <TextView android:id="@+id/tv_time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="14sp" android:textColor="@android:color/darker_gray" android:text="刷新时间" /> </LinearLayout> </LinearLayout>

自定义动画indeterminate_drawable.xml

<?xml version="1.0" encoding="utf-8"?> <rotate xmlns:android="http://schemas.android.com/apk/res/android" android:fromDegrees="0" android:pivotX="50%" android:pivotY="50%" android:drawable="@drawable/indicate_rotate" android:toDegrees="360"> </rotate>尾部的布局layout_tail.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:orientation="horizontal" > <ProgressBar android:layout_width="30dp" android:layout_height="30dp" android:layout_marginTop="10dp" android:layout_marginBottom="10dp" android:indeterminate="true" android:indeterminateDrawable="@drawable/indeterminate_drawable" android:indeterminateDuration="1000" /> <TextView android:layout_width="wrap_content" android:layout_marginTop="10dp" android:layout_marginBottom="10dp" android:layout_height="wrap_content" android:textColor="#aa000000" android:layout_marginLeft="15dp" android:textSize="20sp" android:text="加载更多..."/> </LinearLayout>自定义布局的逻辑文件RefreshListView.java package com.ldw.refresh; import java.text.SimpleDateFormat; import java.util.Date; import android.content.Context; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; 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; /* * 自定义listView */ public class RefreshListView extends ListView implements OnScrollListener{ //初始化head private View headerView;//headerView private int headerViewHeight;//headerView高 //初始化布局 private ImageView iv_arrow; private ProgressBar pb_rotate; private TextView tv_state,tv_time; //初始化尾部 private View footerView; private int footerViewHeight; private int downY;//按下时y坐标 //下拉刷新的三个状态 private final int PULL_REFRESH = 0;//下拉刷新的状态head没有拉完 private final int RELEASE_REFRESH = 1;//松开刷新的状态,head拉完了 private final int REFRESHING = 2;//正在刷新的状态 //初始化当前的刷新状态 private int currentState = PULL_REFRESH; //定义旋转动画,向上向下箭头的动画 private RotateAnimation upAnimation,downAnimation; //当前是否正在处于加载更多,默认不是加载更多 private boolean isLoadingMore = false; public RefreshListView(Context context) { super(context); init(); } public RefreshListView(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init(){ //设置一个滚动监听器 setOnScrollListener(this); initHeadView(); initRotateAnimation(); initFooterView(); } //初始化listView的时候添加head private void initHeadView() { headerView = View.inflate(getContext(), R.layout.layout_head, null); iv_arrow = (ImageView) headerView.findViewById(R.id.iv_arrow); pb_rotate = (ProgressBar) headerView.findViewById(R.id.pb_rotate); tv_state = (TextView) headerView.findViewById(R.id.tv_state); tv_time = (TextView) headerView.findViewById(R.id.tv_time); //通知系统测量view headerView.measure(0, 0); //获取到高度 headerViewHeight = headerView.getMeasuredHeight(); //初始化的时候,设置padding来隐藏head headerView.setPadding(0, -headerViewHeight, 0, 0); //listView就会有head了 addHeaderView(headerView); } //初始化最下面的加载部分 private void initFooterView() { //填充最下面的部分 footerView = View.inflate(getContext(), R.layout.layout_footer, null); footerView.measure(0, 0);//主动通知系统去测量该view; footerViewHeight = footerView.getMeasuredHeight(); //默认是隐藏起来的 footerView.setPadding(0, -footerViewHeight, 0, 0); //添加到底部 addFooterView(footerView); } //旋转动画 private void initRotateAnimation() { //动画 upAnimation = new RotateAnimation(0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); //持续的时间 upAnimation.setDuration(300); //保持结束的状态 upAnimation.setFillAfter(true); downAnimation = new RotateAnimation(-180, -360, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); downAnimation.setDuration(300); downAnimation.setFillAfter(true); } //触摸事件 @Override public boolean onTouchEvent(MotionEvent ev) { switch (ev.getAction()) { //按下的时候 case MotionEvent.ACTION_DOWN: downY = (int) ev.getY(); break; //移动的时候 case MotionEvent.ACTION_MOVE: //移动的相对距离 int deltaY =(int) (ev.getY() - downY); //更新padding,出现head移动的现象 int paddingTop = -headerViewHeight + deltaY; //设置新的padding,,当前的position为0的时候不让listView滑动 //listView下滑的时候走这里deltaY为正,显示headd,最后执行return true //listView上移的时候deltaY为负不走这里可以滑动listView if(paddingTop>-headerViewHeight && getFirstVisiblePosition()==0){ headerView.setPadding(0, paddingTop, 0, 0); //head全部显示了,状态变为松开刷新 if(paddingTop>=0 && currentState==PULL_REFRESH){ //从下拉刷新进入松开刷新状态 currentState = RELEASE_REFRESH; refreshHeaderView(); } //head还没有拉完,状态是下拉刷新 else if (paddingTop<0 && currentState==RELEASE_REFRESH) { //进入下拉刷新状态 currentState = PULL_REFRESH; refreshHeaderView(); } //拦截TouchMove,不让listview处理该次move事件,会造成listview无法滑动 return true; } break; //松开就隐藏head case MotionEvent.ACTION_UP: //当前的状态是下拉刷新的时候隐藏head if(currentState == PULL_REFRESH){ //隐藏head } //当前的状态是松开刷新的时候,让head全部显示 else if (currentState==RELEASE_REFRESH) { //head全部显示 headerView.setPadding(0, 0, 0, 0); //状态变为正在刷新 currentState = REFRESHING; refreshHeaderView(); //调用接口方法,需要进行刷新了 if(listener!=null){ listener.onPullRefresh(); } } break; } return super.onTouchEvent(ev); } /* * 更据当前的状态更新head的显示 */ private void refreshHeaderView(){ switch (currentState) { case PULL_REFRESH: tv_state.setText("下拉刷新"); iv_arrow.startAnimation(downAnimation); break; case RELEASE_REFRESH: tv_state.setText("松开刷新"); iv_arrow.startAnimation(upAnimation); break; case REFRESHING: //因为向上的旋转动画有可能没有执行完 iv_arrow.clearAnimation(); //箭头消失 iv_arrow.setVisibility(View.INVISIBLE); //进度体哦啊可见 pb_rotate.setVisibility(View.VISIBLE); tv_state.setText("正在刷新..."); break; } } //完成刷新,恢复之前的状态一般是异步加载,在你获取完数据并更新完adater之后,去在UI线程中调用该方法 //子线程中操作 public void completeRefresh(){ if(isLoadingMore){ //重置footerView状态,隐藏相关条目 footerView.setPadding(0, -footerViewHeight, 0, 0); //可以继续刷新 isLoadingMore = false; }else { headerView.setPadding(0, -headerViewHeight, 0, 0); //状态改变,由正在刷新变成完成刷新 currentState = PULL_REFRESH; pb_rotate.setVisibility(View.INVISIBLE); //箭头消失 iv_arrow.setVisibility(View.INVISIBLE); tv_state.setText("下拉刷新"); tv_time.setText("最后刷新时间" + getCurrentTime()); } } //获取时间 private String getCurrentTime(){ //时间写的格式如下 SimpleDateFormat format = new SimpleDateFormat("yy-MM-dd HH:mm:ss"); return format.format(new Date()); } //接口变量创建 private OnRefreshListener listener; public void setOnRefreshListener(OnRefreshListener listener){ this.listener = listener; } //创建接口 public interface OnRefreshListener{ void onPullRefresh(); void onLoadingMore(); } //滚动的接口方法,滚动状态的改变 @Override public void onScrollStateChanged(AbsListView view, int scrollState) { //SCROLL_STATE_IDLE闲置状态,手指松开的时候的状态 //SCROLL_STATE_TOUCH_SCROLL:手指触摸滑动,就是按着来滑动 //SCROLL_STATE_FLING:快速滑动后松开,惯性 if(scrollState==OnScrollListener.SCROLL_STATE_IDLE && getLastVisiblePosition()==(getCount()-1) &&!isLoadingMore){ isLoadingMore = true; footerView.setPadding(0, 0, 0, 0);//显示出footerView setSelection(getCount());//让listview最后一条显示出来 //使用接口的监听,需要加载更多 if(listener!=null){ listener.onLoadingMore(); } } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { // TODO Auto-generated method stub } }页面的逻辑文件MainActivity.java package com.ldw.refresh; import java.util.ArrayList; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.SystemClock; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.widget.BaseAdapter; import android.widget.TextView; import com.ldw.refresh.RefreshListView.OnRefreshListener; public class MainActivity extends Activity { private RefreshListView refreshListView;//初始化自定义listView private ArrayList<String> list = new ArrayList<String>(); private MyAdapter adapter; private Handler handler = new Handler(){ public void handleMessage(android.os.Message msg) { //更新UI adapter.notifyDataSetChanged(); refreshListView.completeRefresh(); }; }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); initView(); initData(); } private void initView() { //设置没有标题的window样式 requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_main); refreshListView = (RefreshListView) findViewById(R.id.refreshListView); } private void initData() { //初始化列表中的数据 for(int i = 0; i < 20; i++){ list.add("1300000000" + i); } //初始化头部的填充 final View headView = View.inflate(this, R.layout.layout_head, null); /*在填充自定义的listView中直接实现 //监听headView,xml文件是异步加载的,一开始没有获取到高度 headView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { headView.getViewTreeObserver().removeGlobalOnLayoutListener(this); //获取到headView高度来,设置隐藏的padding int headViewHeight = headView.getHeight(); //设置padding headView.setPadding(0, -headViewHeight, 0, 0); //添加刷新的布局,添加到自定义listView的顶部,必须在setAdapter前面调用 refreshListView.addHeaderView(headView); } }); */ //创建adapter,填充listView adapter = new MyAdapter(); refreshListView.setAdapter(adapter); //监听refreshListView,在创建刷新完listView后调用接口 refreshListView.setOnRefreshListener(new OnRefreshListener(){ //松开进入刷新状态 @Override public void onPullRefresh() { System.out.println("松开状态进入刷新"); requestDataFromServer(false); } @Override public void onLoadingMore() { //加载更多 requestDataFromServer(true); } }); } /** * 模拟向服务器请求数据 */ private void requestDataFromServer(final boolean isLoadingMore){ new Thread(){ public void run() { //模拟请求服务器的一个时间长度,休眠3s SystemClock.sleep(3000); if(isLoadingMore){ list.add("加载更多的数据-1"); list.add("加载更多的数据-2"); list.add("加载更多的数据-3"); }else { list.add(0, "下拉刷新的数据"); } //在UI线程更新UI handler.sendEmptyMessage(0); }; }.start(); } class MyAdapter extends BaseAdapter{ @Override public int getCount() { return list.size(); } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { //创建一个TextView控件并设置属性 TextView textView = new TextView(MainActivity.this); //设置内边距 textView.setPadding(20, 20, 20, 20); //设置字体大小 textView.setTextSize(18); //设置文本内容 textView.setText(list.get(position)); return textView; } } }

转载请注明原文地址: https://www.6miu.com/read-1014.html

最新回复(0)