Android实践之带加载效果的下拉刷新上拉加载更多

Android实践之带加载效果的下拉刷新上拉加载更多,第1张

概述前言之前写的一个LoadingBar,这次把LoadingBar加到下拉刷新的头部。从头写一个下拉刷新,附赠上拉加载更多。下面话不多说了,来一起看看详细的介绍吧。

前言

之前写的一个LoadingBar,这次把Loadingbar加到下拉刷新的头部。从头写一个下拉刷新,附赠上拉加载更多。下面话不多说了,来一起看看详细的介绍吧。

效果图:

实现过程

首先是自定义属性,attrs.xml中定义头部的高度和上下的padding。

####attrs.xml####

<?xml version="1.0" enCoding="utf-8"?><resources> <declare-styleable name="PPRefreshVIEw_header"> <attr name="header_height" format="dimension"/> <attr name="header_padding" format="dimension"/> </declare-styleable></resources>

然后是头部的文件,里面放了一个TextVIEw和一个图片

header_layout.xml####

<?xml version="1.0" enCoding="utf-8"?><relativeLayout xmlns:androID="http://schemas.androID.com/apk/res/androID" androID:layout_wIDth="match_parent" androID:layout_height="50dp" androID:orIEntation="vertical"> <ImageVIEw androID:src="@mipmap/down" androID:layout_centerVertical="true" androID:ID="@+ID/icon" androID:layout_wIDth="20dp" androID:layout_height="20dp" androID:layout_toleftOf="@+ID/text" androID:layout_marginRight="5dp"/> <TextVIEw androID:ID="@+ID/text" androID:layout_wIDth="wrap_content" androID:layout_height="wrap_content" androID:layout_centerInParent="true" androID:text="下拉刷新" /></relativeLayout>

然后是布局文件,让PPRefreshVIEw作为父布局,下面可以放AbsListVIEw的子类。

activity_main.xml####

<?xml version="1.0" enCoding="utf-8"?><relativeLayout xmlns:androID="http://schemas.androID.com/apk/res/androID" xmlns:ppRefreshVIEw="http://schemas.androID.com/apk/res-auto" xmlns:tools="http://schemas.androID.com/tools" androID:layout_wIDth="match_parent" androID:layout_height="match_parent" androID:background="@color/white" tools:context="top.greendami.greendami.MainActivity"> <top.greendami.greendami.PPRefreshVIEw ppRefreshVIEw:header_height="50dp" ppRefreshVIEw:header_padding="10dp" androID:ID="@+ID/swipeRefreshLayout" androID:layout_wIDth="match_parent" androID:layout_height="match_parent" androID:background="#d4d4d4"> <ListVIEw androID:background="@color/white" androID:ID="@+ID/List" androID:layout_wIDth="match_parent" androID:layout_height="match_parent"></ListVIEw> </top.greendami.greendami.PPRefreshVIEw></relativeLayout>

最后是重点,下拉刷新的控件。

"精心"准备了一张图

####PPRefreshVIEw.java####

package top.greendami.greendami;package com.allrun.arsmartelevatorformanager.Widget;import androID.content.Context;import androID.content.res.TypedArray;import androID.graphics.Canvas;import androID.support.v7.Widget.RecyclerVIEw;import androID.util.AttributeSet;import androID.vIEw.LayoutInflater;import androID.vIEw.MotionEvent;import androID.vIEw.VIEw;import androID.vIEw.VIEwConfiguration;import androID.vIEw.VIEwGroup;import androID.vIEw.animation.Animation;import androID.vIEw.animation.RotateAnimation;import androID.Widget.ImageVIEw;import androID.Widget.TextVIEw;import com.allrun.arsmartelevatorformanager.R;import com.allrun.arsmartelevatorformanager.util.DPUnitUtil;/** * Created by GreendamI on 2017/3/21. */public class PPRefreshVIEw extends VIEwGroup { Context context; RecyclerVIEw mListVIEw; PPVIEw mPPVIEw; VIEw header; TextVIEw Title; ImageVIEw mImage;//箭头 int Listtop = 0; float headerHeight = 10 + 30 + 10;//header的高度,上留白 + 文字(PPVIEw)高度 + 下留白 float headerpadding = 10;//上留白,下留白 private int mYDown,mLastY; //最短滑动距离 int a = 0; RotateAnimation mRotateAnimation; int state = 0; //0,正常;1,下拉;2,松开 public voID setPPRefreshVIEwListener(PPRefreshVIEwListener mPPRefreshVIEwListener) { this.mPPRefreshVIEwListener = mPPRefreshVIEwListener; } PPRefreshVIEwListener mPPRefreshVIEwListener; public PPRefreshVIEw(Context context) { super(context); this.context = context; } public PPRefreshVIEw(Context context,AttributeSet attrs) { super(context,attrs); this.context = context; //px转dp a = DPUnitUtil.px2dip(context,VIEwConfiguration.get(context).getScaledDoubleTapSlop()); TypedArray b = context.obtainStyledAttributes(attrs,R.styleable.PPRefreshVIEw_header); headerHeight = b.getDimension(R.styleable.PPRefreshVIEw_header_header_height,100); headerpadding = b.getDimension(R.styleable.PPRefreshVIEw_header_header_padding,10); b.recycle(); initAnima(); } private voID initAnima() { //箭头旋转 mRotateAnimation = new RotateAnimation(0,180,Animation.relative_TO_SELF,0.5f,0.5f); mRotateAnimation.setFillAfter(true); mRotateAnimation.setDuration(200); } @OverrIDe protected voID onMeasure(int wIDthMeasureSpec,int heightmeasureSpec) { if (mPPVIEw != null) { mPPVIEw.measure(wIDthMeasureSpec,(int) (headerHeight- 2 * headerpadding)); } if (header != null) { header.measure(wIDthMeasureSpec,(int) (headerHeight- 2 * headerpadding)); } super.onMeasure(wIDthMeasureSpec,heightmeasureSpec); } @OverrIDe protected voID onLayout(boolean changed,int l,int t,int r,int b) { if (mListVIEw == null && getChildCount() == 1) { mListVIEw = (RecyclerVIEw)getChildAt(0); mListVIEw.setonScrollListener(new RecyclerVIEw.OnScrollListener() { @OverrIDe public voID onScrolled(RecyclerVIEw recyclerVIEw,int dx,int dy) {  super.onScrolled(recyclerVIEw,dx,dy);  if(!recyclerVIEw.canScrollVertically(1)){  //添加外部回调  if(mPPRefreshVIEwListener != null){  mPPRefreshVIEwListener.LoadMore();  }  } } }); } if (mListVIEw != null) { mListVIEw.layout(l,Listtop,getMeasureDWIDth(),b); } if (mPPVIEw != null) { //top:文字(PPVIEw)高度 + 下留白 mPPVIEw.layout(l,(int)(Listtop - headerHeight + headerpadding),r,Listtop); } if (header != null) { //top:文字(PPVIEw)高度 + 下留白 header.layout(l,Listtop); } } @OverrIDe protected voID dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas); //松开手指,List回到顶部 if (state == 2) { Listtop = Listtop - 25; if (Listtop < headerHeight) { Listtop = (int)headerHeight; } requestLayout(); } //刷新完毕,关闭header if (state == 0 && Listtop > 0) { Listtop = Listtop - 25; if (Listtop < 0) { Listtop = 0; } requestLayout(); } } @OverrIDe public boolean dispatchtouchEvent(MotionEvent event) { final int action = event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: // 按下 mYDown = (int) event.getRawY(); break; case MotionEvent.ACTION_MOVE: // 移动 mLastY = (int) event.getRawY(); if (!mListVIEw.canScrollVertically(-1) && mLastY > mYDown &&(mLastY - mYDown) > a) {  state = 1;  Listtop = mLastY - mYDown;  if (mPPVIEw != null) {  removeVIEw(mPPVIEw);  mPPVIEw = null;  }  if (header == null) {  header = LayoutInflater.from(context).inflate(R.layout.header_layout,null,false);  Title = ((TextVIEw) header.findVIEwByID(R.ID.text));  mImage = ((ImageVIEw) header.findVIEwByID(R.ID.icon));  addVIEw(header);  }  if (Title != null && (mLastY - mYDown) > a * 2f) {  Title.setText("松开刷新");  if (mImage.getAnimation() == null) {  mImage.startAnimation(mRotateAnimation);  }  }  if (Title != null && (mLastY - mYDown) < a * 2f) {  Title.setText("下拉刷新");  mImage.setimageResource(R.mipmap.down);  }  requestLayout();  //已经判断是下拉刷新,拦截手势  return false; } break; case MotionEvent.ACTION_UP: // 抬起// if (canLoad()) {//  loadData();// } //松手的时候,把文字标题去掉 if (header != null) {  removeVIEw(header);  header = null; } //如果之前是下拉状态,就添加PPVIEw if (mPPVIEw == null && state == 1) {  //添加外部回调  if(mPPRefreshVIEwListener != null){  mPPRefreshVIEwListener.onRefresh();  }  mPPVIEw = new PPVIEw(context);  addVIEw(mPPVIEw);  mYDown = 0;  mLastY = 0;  state = 2;  requestLayout(); } break; default: break; } return super.dispatchtouchEvent(event); } /** * 收起下拉刷新的header,刷新结束 */ public voID RefreshOver() { if (mPPVIEw != null) { removeVIEw(mPPVIEw); mPPVIEw = null; } if (header != null) { removeVIEw(header); header = null; Title = null; mImage = null; } state = 0; } public voID setRefreshing(boolean b) { if(!b){ state = 0; postInvalIDate(); }else{ state = 2; postInvalIDate(); } } public interface PPRefreshVIEwListener{ voID onRefresh(); voID LoadMore(); }}

主要思路是监听手势的滑动距离,如果ListVIEw已经划到顶部,则ListVIEw跟随手指位置,并添加header。放开手指后,ListVIEw慢慢回到顶部。

外部回调。监听下拉和上拉。

 mSwipeRefreshLayout.setPPRefreshVIEwListener(new PPRefreshVIEw.PPRefreshVIEwListener() { @OverrIDe public voID onRefresh() { Toast.makeText(MainActivity.this,"亲,刷新了",Toast.LENGTH_SHORT).show(); data.add("测试数据100"); mAdapter.notifyDataSetChanged(); } @OverrIDe public voID LoadMore() { Toast.makeText(MainActivity.this,"加载更多",Toast.LENGTH_SHORT).show(); } });refreshLayout.setRefreshing(false);;//刷新完毕

差点忘了粘连小球的VIEw。

####PPVIEw.java####package top.greendami.greendami;import androID.content.Context;import androID.graphics.Canvas;import androID.graphics.Paint;import androID.graphics.Path;import androID.support.annotation.Nullable;import androID.util.AttributeSet;import androID.vIEw.VIEw;/** * Created by Greendami on 2017/3/17. */public class PPVIEw extends VIEw { String TAG = "PPVIEw"; //动画开关 boolean isLoading = true; Context mContext; private int mWIDth = 100; private int mheight = 100; public int mcolor; public Paint mPaint = new Paint(); float time = 0; //小球与中间打球的最远距离 float distance = 100; public PPVIEw(Context context) { super(context); mContext = context; mcolor = context.getResources().getcolor(R.color.colorPrimary); init(); } public PPVIEw(Context context,@Nullable AttributeSet attrs) { super(context,attrs); mContext = context; mcolor = context.getResources().getcolor(R.color.colorPrimary); init(); } private voID init() { mPaint.setAntiAlias(true); mPaint.setcolor(mcolor); } @OverrIDe protected voID onMeasure(int wIDthMeasureSpec,int heightmeasureSpec) { super.onMeasure(wIDthMeasureSpec,heightmeasureSpec); int wIDthSpecsize = MeasureSpec.getSize(wIDthMeasureSpec); int heightSpecsize = MeasureSpec.getSize(heightmeasureSpec); //宽度至少是高度的4倍 if (wIDthSpecsize < 4 * heightSpecsize) { wIDthSpecsize = 4 * heightSpecsize; } mWIDth = wIDthSpecsize; mheight = heightSpecsize; distance = 1.2f * mheight; setMeasuredDimension(wIDthSpecsize,heightSpecsize); } @OverrIDe protected voID onDraw(Canvas canvas) { super.onDraw(canvas); if (isLoading) { //大圆半径 float bigR = mheight * 0.32f + mheight * 0.03f * Math.abs((float) Math.sin(Math.toradians(time))); float smallR = mheight * 0.17f + mheight * 0.03f * Math.abs((float) Math.cos(Math.toradians(time))); float bigx = (getWIDth()) / 2; //画中间大圆 canvas.drawCircle(bigx,mheight / 2,bigR,mPaint); float smalx = getSmallCenterX(); //画小圆 canvas.drawCircle(smalx,smallR,mPaint); //画链接 //小球在右侧 if (smalx > bigx) { Path path = new Path(); //上面的贝塞尔曲线的第一个点,在大圆身上 float x1 = bigx + bigR * (float) Math.cos(Math.toradians(time)); float y1 = mheight / 2 - bigR * (float) Math.sin(Math.toradians(time)); if (y1 > mheight / 2 - smallR) {  y1 = mheight / 2 - smallR;  x1 = bigx + (float) (Math.sqrt(bigR * bigR - smallR * smallR)); } //上面的贝塞尔曲线的第三个点,在小圆身上 float x2 = smalx - smallR * (float) Math.cos(Math.toradians(time)); float y2 = mheight / 2 - smallR * (float) Math.sin(Math.toradians(time)); if (y2 > mheight / 2 - smallR * 0.8) {  y2 = mheight / 2 - smallR * 0.8f;  x2 = smalx - smallR * (float) (Math.sqrt(1-0.64f)); } //下面的贝塞尔曲线的第三个点,在小圆身上 float x3 = smalx - smallR * (float) Math.cos(Math.toradians(time)); float y3 = mheight / 2 + smallR * (float) Math.sin(Math.toradians(time)); if (y3 < mheight / 2 + smallR * 0.8) {  y3 = mheight / 2 + smallR * 0.8f;  x3 = smalx - smallR * (float) (Math.sqrt(1-0.64f)); } //下面的贝塞尔曲线的第一个点,在大圆身上 float x4 = bigx + bigR * (float) Math.cos(Math.toradians(time)); float y4 = mheight / 2 + bigR * (float) Math.sin(Math.toradians(time)); if (y4 < mheight / 2 + smallR) {  y4 = mheight / 2 + smallR;  x4 = bigx + (float) (Math.sqrt(bigR * bigR - smallR * smallR)); } path.moveto(x1,y1); path.quadTo((bigx + smalx) / 2,x2,y2); // 绘制贝赛尔曲线(Path) path.lineto(x3,y3); path.quadTo((bigx + smalx) / 2,x4,y4); canvas.drawPath(path,mPaint); } //小球在左侧 if (smalx < bigx) { Path path = new Path(); float x1 = bigx + bigR * (float) Math.cos(Math.toradians(time)); float y1 = mheight / 2 - bigR * (float) Math.sin(Math.toradians(time)); if (y1 > mheight / 2 - smallR) {  y1 = mheight / 2 - smallR;  x1 = bigx - (float) (Math.sqrt(bigR * bigR - smallR * smallR)); } float x2 = smalx - smallR * (float) Math.cos(Math.toradians(time)); float y2 = mheight / 2 - smallR * (float) Math.sin(Math.toradians(time)); if (y2 > mheight / 2 - smallR * 0.8) {  y2 = mheight / 2 - smallR * 0.8f;  x2 = smalx + smallR * (float) (Math.sqrt(1-0.64f)); } float x3 = smalx - smallR * (float) Math.cos(Math.toradians(time)); float y3 = mheight / 2 + smallR * (float) Math.sin(Math.toradians(time)); if (y3 < mheight / 2 + smallR * 0.8) {  y3 = mheight / 2 + smallR * 0.8f;  x3 = smalx + smallR * (float) (Math.sqrt(1-0.64f)); } float x4 = bigx + bigR * (float) Math.cos(Math.toradians(time)); float y4 = mheight / 2 + bigR * (float) Math.sin(Math.toradians(time)); if (y4 < mheight / 2 + smallR) {  y4 = mheight / 2 + smallR;  x4 = bigx - (float) (Math.sqrt(bigR * bigR - smallR * smallR)); } path.moveto(x1,y2); // 绘制贝赛尔曲线(Path) path.lineto(x3,y3); path.quadTo((bigx + smalx) / 2,mPaint); } postInvalIDate(); } } //计算小球的X坐标 private float getSmallCenterX() { //此处控制速度 time = time + 4f; return mWIDth / 2 + distance * (float) Math.cos(Math.toradians(time)); }}

两张素材


总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对编程小技巧的支持。

总结

以上是内存溢出为你收集整理的Android实践之带加载效果的下拉刷新上拉加载更多全部内容,希望文章能够帮你解决Android实践之带加载效果的下拉刷新上拉加载更多所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1143364.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存