热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

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

这篇文章主要给大家介绍了关于Android实践之下拉刷新上拉加载更多的相关资料,实现的效果在现在的很多项目中都能用到,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧。

前言

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

效果图:

实现过程

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

####attrs.xml####

<&#63;xml version="1.0" encoding="utf-8"&#63;>

 
 
 
 

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

header_layout.xml####

<&#63;xml version="1.0" encoding="utf-8"&#63;>

 
 

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

activity_main.xml####

<&#63;xml version="1.0" encoding="utf-8"&#63;>

 
 
 

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

"精心"准备了一张图

####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, Animation.RELATIVE_TO_SELF, 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, (int)(listTop - headerHeight + headerpadding), r, listTop);
 }
 }
 @Override
 protected void dispatchDraw(Canvas canvas) {
 super.dispatchDraw(canvas);
 //松开手指,list回到顶部
 if (state == 2) {
 listTop = listTop - 25;
 if (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) 

主要思路是监听手势的滑动距离,如果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, mheight / 2, 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) {
  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 

两张素材


总结

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


推荐阅读
  • 前期部署1.JDK安装,配置PATH2.下载spark-1.6.1-bin-hadoop2.6.tgz,并上传到服务器解压3.在 usr 下创建软链接到目标文件夹4.修改配置文件, ... [详细]
  • android RadioButton放大或者缩小
    RadioButtonandroid并没有提供方法来控制按钮的大小,我自己在网 ... [详细]
  • 为什么SpringBoot的jar可以直接运行
    这篇文章主要介绍了为什么SpringBoot的jar可以直接运行,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着 ... [详细]
  • 1、什么是Struts?   Struts是基于MVC的轻量级框架,主要处理请求分发的问题,重心在控制层和表现层。   –基于MVC:实现了MVC,满足MVC的设计思想。   –轻 ... [详细]
  • 1.什么时候使用到当使用到context:annotation-config或者context:component-scan配置的时候,及声明做为其它BeanFac ... [详细]
  • key_ctrl主要用于监控键盘按钮,定义按钮功能,便于智能车的控制和调试该包主要包含:key.hkey_ctrl_node.cpp ... [详细]
  • @JsonField和@JsonProperty的使用和区别
    @JsonFieldJsonField是位于fastjson包下的,实体类序列化为json字符串的时候,此类的原字段,序列化为json中的规定的字段配合JSON.toJSONStr ... [详细]
  • WCF多服务配置失败
    问题首先来看一下项目结构如图中所示,我需要在App.config文件中配置两个服务:IBookSerivices和IWcfSvrCallBack配置的结果如下面的XML代码 ... [详细]
  • [191]python3.6下scrapy框架的安装
    首先考虑使用最简单的方法安装pipinstallscrapy命令安装,提示FailedbuildingwheelforTwistedMicrosoftVisual ... [详细]
  • 1、war是一个web模块,其中需要包括WEB-INF,是可以直接运行的WEB模块;jar一般只是包括一些class文件,在声明了Main_class之后是可以用java命令运行的。2、wa ... [详细]
  • DimmyCompasnewMySTAComponent()PublicSubPage_Load()myComp.Name=BobEndSub  首选机 ... [详细]
  • spring data jpa介绍以及基础示例
    JPA介绍JPA的全称是JavaPersistenceAPI,提供了一个规范,用于将数据通过Java对象持久化、读取和管理数据库中的关系表。所以JPA本质上就是一种ORM规 ... [详细]
  • 我有一个用C#编写的服务器,需要从Java1.6与之对话.我需要连接到服务器,保持连接,并双向发送消息.消息是一个int(消息的长度),然后是一个XML文件.做这个的最好方式是什么 ... [详细]
  • MyBatis笔记04分页查询、resultMap的简单使用
    MyBatis笔记04-----分页查询、resultMap的简单使用-分页查询1、分页查询的好处MyBatis作为持久层框架,主要任务就是操作数据库,即是对数据的增、删、查 ... [详细]
  • 小编典典UCanAccess是一个纯JavaJDBC驱动程序,它使我们无需使用ODBC即可读写Access数据库。它使用其他两个软件包Jackcess和HSQLDB来 ... [详细]
author-avatar
手机用户2502925313
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有