大佬教程收集整理的这篇文章主要介绍了Android实践之带加载效果的下拉刷新上拉加载更多,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
前言
之前写的一个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>
header_layout.xml####
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://scheR_950_11845@as.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://scheR_950_11845@as.android.com/apk/res/android" xmlns:pprefreshView="http://scheR_950_11845@as.android.com/apk/res-auto" xmlns:tools="http://scheR_950_11845@as.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,(@R_674_10185@ (headerHeight- 2 * headerpadding)); } if (header != null) { header.measure(widthMeasureSpec,(@R_674_10185@ (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,(@R_674_10185@(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 = (@R_674_10185@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 = (@R_674_10185@ event.getRawY(); break; case MotionEvent.ACTION_MOVE: // 移动 mLastY = (@R_674_10185@ 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,mPa@R_674_10185@; float smalx = getsmallCenterX(); //画小圆 canvas.drawCircle(smalx,smallR,mPa@R_674_10185@; //画链接 //小球在右侧 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,mPa@R_674_10185@; } //小球在左侧 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,mPa@R_674_10185@; } posTinvalidate(); } } //计算小球的X坐标 private float getsmallCenterX() { //此处控制速度 time = time + 4f; return mWidth / 2 + distance * (float) Math.cos(Math.toradians(timE)); } }
两张素材
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对编程小技巧的支持。
以上是大佬教程为你收集整理的Android实践之带加载效果的下拉刷新上拉加载更多全部内容,希望文章能够帮你解决Android实践之带加载效果的下拉刷新上拉加载更多所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。