Android自定义渐变式炫酷ListView下拉刷新动画

本文实例为大家分享了自定义渐变式炫酷动画的ListView下拉刷新,供大家参考,具体内容如下

主要要点

listview刷新过程中主要有三个步骤当前:状态为下拉刷新,当前状态为下拉刷新,当前状态为放开刷新,当前状态为正在刷新;主要思路为三个步骤分别对应三个自定义的view;即ibuRefreshFirstStepView,ibuRefreshSecondStepView,ibuRefreshThirdStepView。

效果图

ibuRefreshFirstStepView代码,例如:

private Bitmap initialBitmap; private float mCurrentProgress; private Bitmap scaledBitmap; public ibuRefreshFirstStepView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context); } public ibuRefreshFirstStepView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public ibuRefreshFirstStepView(Context context) { super(context); init(context); } private void init(Context context) { //这个就是那个火箭图片 initialBitmap = Bitmap.createBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.img_huojian1)); } /** * 重写onMeasure方法主要是设置wrap_content时 View的大小 * @param widthMeasureSpec * @param heightMeasureSpec */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //根据设置的宽度来计算高度 设置为符合第二阶段娃娃图片的宽高比例 setMeasuredDimension(measureWidth(widthMeasureSpec),measureWidth(widthMeasureSpec)*initialBitmap.getHeight()/initialBitmap.getWidth()); } /** * 当wrap_content的时候,宽度即为第二阶段娃娃图片的宽度 * @param widMeasureSpec * @return */ private int measureWidth(int widMeasureSpec){ int result = 0; int size = MeasureSpec.getSize(widMeasureSpec); int mode = MeasureSpec.getMode(widMeasureSpec); if (mode == MeasureSpec.EXACTLY){ result = size; }else{ result = initialBitmap.getWidth(); if (mode == MeasureSpec.AT_MOST){ result = Math.min(result,size); } } return result; } /** * 在onLayout里面获得测量后View的宽高 * @param changed * @param left * @param top * @param right * @param bottom */ @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); // 给火箭图片进行等比例的缩放 scaledBitmap = Bitmap.createScaledBitmap(initialBitmap,89,110, false); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //这个方法是对画布进行缩放,从而达到椭圆形图片的缩放,第一个参数为宽度缩放比例,第二个参数为高度缩放比例, // canvas.scale(mCurrentProgress, mCurrentProgress, measuredWidth/2, measuredHeight/2); //将等比例缩放后的椭圆形画在画布上面 canvas.drawBitmap(scaledBitmap,90,dip2px(getContext(),80*mCurrentProgress),null); } /** * 根据手机的分辨率从 dp 的单位 转成为 px(像素) */ public static int dip2px(Context context, float dpValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } /** * 设置缩放比例,从0到1 0为最小 1为最大 * @param currentProgress */ public void setCurrentProgress(float currentProgress){ mCurrentProgress = currentProgress; } }

ibuRefreshSecondStepView代码,例如:

private Bitmap endBitmap,scaledBitmap; public ibuRefreshSecondStepView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } public ibuRefreshSecondStepView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public ibuRefreshSecondStepView(Context context) { super(context); init(); } private void init() { endBitmap = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.img_huojian2), 89, 110, false); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(measureWidth(widthMeasureSpec), measureWidth(widthMeasureSpec) * endBitmap.getHeight() / endBitmap.getWidth()); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); scaledBitmap = Bitmap.createScaledBitmap(endBitmap, 89, 110, false); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawBitmap(endBitmap, 90, dip2px(getContext(), 80 * 1), null); } /** * 根据手机的分辨率从 dp 的单位 转成为 px(像素) */ public static int dip2px(Context context, float dpValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } private int measureWidth(int widthMeasureSpec){ int result = 0; int size = MeasureSpec.getSize(widthMeasureSpec); int mode = MeasureSpec.getMode(widthMeasureSpec); if (mode == MeasureSpec.EXACTLY) { result = size; }else { result = endBitmap.getWidth(); if (mode == MeasureSpec.AT_MOST) { result = Math.min(result, size); } } return result; } }

ibuRefreshThirdStepView代码,例如:

private Bitmap endBitmap,scaledBitmap; public ibuRefreshThirdStepView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } public ibuRefreshThirdStepView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public ibuRefreshThirdStepView(Context context) { super(context); init(); } private void init() { endBitmap = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.img_huojian3), 89, 170, false); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawBitmap(endBitmap, 90, dip2px(getContext(), 40 * 1), null); } /** * 根据手机的分辨率从 dp 的单位 转成为 px(像素) */ public static int dip2px(Context context, float dpValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(measureWidth(widthMeasureSpec), measureWidth(widthMeasureSpec)*endBitmap.getHeight()/endBitmap.getWidth()); } private int measureWidth(int widthMeasureSpec){ int result = 0; int size = MeasureSpec.getSize(widthMeasureSpec); int mode = MeasureSpec.getMode(widthMeasureSpec); if (mode == MeasureSpec.EXACTLY) { result = size; }else { result = endBitmap.getWidth(); if (mode == MeasureSpec.AT_MOST) { result = Math.min(result, size); } } return result; }

代码块

IbuListView 代码,例如:

private static final int DONE = 0; private static final int PULL_TO_REFRESH = 1; private static final int RELEASE_TO_REFRESH = 2; private static final int REFRESHING = 3; private static final int RATIO = 3; private RelativeLayout headerView; private int headerViewHeight; private float startY; private float offsetY; private TextView tv_pull_to_refresh; private OnMeiTuanRefreshListener mOnRefreshListener; private int state; private int mFirstVisibleItem; private boolean isRecord; private boolean isEnd; private boolean isRefreable; private FrameLayout mAnimContainer; // private Animation animation; private SimpleDateFormat format; private ibuRefreshFirstStepView mFirstView; private ibuRefreshSecondStepView mSecondView; private AnimationDrawable secondAnim; private ibuRefreshThirdStepView mThirdView; private AnimationDrawable thirdAnim; public IbuListView(Context context) { super(context); init(context); } public IbuListView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public IbuListView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } public interface OnMeiTuanRefreshListener{ void onRefresh(); } /** * 回调接口,想实现下拉刷新的listview实现此接口 * @param onRefreshListener */ public void setOnMeiTuanRefreshListener(OnMeiTuanRefreshListener onRefreshListener){ mOnRefreshListener = onRefreshListener; isRefreable = true; } /** * 刷新完毕,从主线程发送过来,并且改变headerView的状态和文字动画信息 */ public void setOnRefreshComplete(){ //一定要将isEnd设置为true,以便于下次的下拉刷新 isEnd = true; state = DONE; changeHeaderByState(state); } private ImageView imageViewBack,imageView_B; private void init(Context context) { setOverScrollMode(View.OVER_SCROLL_NEVER); setOnScrollListener(this); headerView = (RelativeLayout) LayoutInflater.from(context).inflate(R.layout.ibu_item, null, false); imageViewBack= (ImageView) headerView.findViewById(R.id.icon_back); imageView_B= (ImageView) headerView.findViewById(R.id.image_b); mFirstView = (ibuRefreshFirstStepView) headerView.findViewById(R.id.first_view); tv_pull_to_refresh = (TextView) headerView.findViewById(R.id.tv_pull_to_refresh); mSecondView = (ibuRefreshSecondStepView) headerView.findViewById(R.id.second_view); mThirdView = (ibuRefreshThirdStepView) headerView.findViewById(R.id.third_view); measureView(headerView); addHeaderView(headerView); headerViewHeight = headerView.getMeasuredHeight(); headerView.setPadding(0, -headerViewHeight, 0, 0); Log.i("zhangqi","headerViewHeight="+headerViewHeight); state = DONE; isEnd = true; isRefreable = false; } @Override public void onScrollStateChanged(AbsListView absListView, int i) { } @Override public void onScroll(AbsListView absListView, int firstVisibleItem, int visibleItemCount, int totalItemCount) { mFirstVisibleItem = firstVisibleItem; } @Override public boolean onTouchEvent(MotionEvent ev) { if (isEnd) {//如果现在时结束的状态,即刷新完毕了,可以再次刷新了,在onRefreshComplete中设置 if (isRefreable) {//如果现在是可刷新状态 在setOnMeiTuanListener中设置为true switch (ev.getAction()){ //用户按下 case MotionEvent.ACTION_DOWN: //如果当前是在listview顶部并且没有记录y坐标 if (mFirstVisibleItem == 0 && !isRecord) { //将isRecord置为true,说明现在已记录y坐标 isRecord = true; //将当前y坐标赋值给startY起始y坐标 startY = ev.getY(); } imageView_B.setVisibility(VISIBLE); break; //用户滑动 case MotionEvent.ACTION_MOVE: //再次得到y坐标,用来和startY相减来计算offsetY位移值 float tempY = ev.getY(); //再起判断一下是否为listview顶部并且没有记录y坐标 if (mFirstVisibleItem == 0 && !isRecord) { isRecord = true; startY = tempY; } //如果当前状态不是正在刷新的状态,并且已经记录了y坐标 if (state!=REFRESHING && isRecord ) { //计算y的偏移量 offsetY = tempY - startY; //计算当前滑动的高度 float currentHeight = (-headerViewHeight+offsetY/3); //用当前滑动的高度和头部headerView的总高度进行比 计算出当前滑动的百分比 0到1 float currentProgress = 1+currentHeight/headerViewHeight; //如果当前百分比大于1了,将其设置为1,目的是让第一个状态的椭圆不再继续变大 if (currentProgress>=1) { currentProgress = 1; } //如果当前的状态是放开刷新,并且已经记录y坐标 if (state == RELEASE_TO_REFRESH && isRecord) { setSelection(0); //如果当前滑动的距离小于headerView的总高度 if (-headerViewHeight+offsetY/RATIO<0) { //将状态置为下拉刷新状态 state = PULL_TO_REFRESH; //根据状态改变headerView,主要是更新动画和文字等信息 changeHeaderByState(state); //如果当前y的位移值小于0,即为headerView隐藏了 }else if (offsetY<=0) { //将状态变为done state = DONE; //根据状态改变headerView,主要是更新动画和文字等信息 changeHeaderByState(state); } } //如果当前状态为下拉刷新并且已经记录y坐标 if (state == PULL_TO_REFRESH && isRecord) { setSelection(0); //如果下拉距离大于等于headerView的总高度 if (-headerViewHeight+offsetY/RATIO>=0) { //将状态变为放开刷新 state = RELEASE_TO_REFRESH; //根据状态改变headerView,主要是更新动画和文字等信息 changeHeaderByState(state); //如果当前y的位移值小于0,即为headerView隐藏了 }else if (offsetY<=0) { //将状态变为done state = DONE; //根据状态改变headerView,主要是更新动画和文字等信息 changeHeaderByState(state); } } //如果当前状态为done并且已经记录y坐标 if (state == DONE && isRecord) { //如果位移值大于0 if (offsetY>=0) { //将状态改为下拉刷新状态 state = PULL_TO_REFRESH; } } //如果为下拉刷新状态 if (state == PULL_TO_REFRESH) { //则改变headerView的padding来实现下拉的效果 headerView.setPadding(0,(int)(-headerViewHeight+offsetY/RATIO) ,0,0); //给第一个状态的View设置当前进度值 mFirstView.setCurrentProgress(currentProgress); //重画 mFirstView.postInvalidate(); } //如果为放开刷新状态 if (state == RELEASE_TO_REFRESH) { //改变headerView的padding值 headerView.setPadding(0,(int)(-headerViewHeight+offsetY/RATIO) ,0, 0); //给第一个状态的View设置当前进度值 mFirstView.setCurrentProgress(currentProgress); //重画 mFirstView.postInvalidate(); } } break; //当用户手指抬起时 case MotionEvent.ACTION_UP: //如果当前状态为下拉刷新状态 if (state == PULL_TO_REFRESH) { //平滑的隐藏headerView this.smoothScrollBy((int)(-headerViewHeight+offsetY/RATIO)+headerViewHeight, 500); //根据状态改变headerView changeHeaderByState(state); } //如果当前状态为放开刷新 if (state == RELEASE_TO_REFRESH) { //平滑的滑到正好显示headerView this.smoothScrollBy((int)(-headerViewHeight+offsetY/RATIO), 500); //将当前状态设置为正在刷新 state = REFRESHING; //回调接口的onRefresh方法 mOnRefreshListener.onRefresh(); //根据状态改变headerView changeHeaderByState(state); } //这一套手势执行完,一定别忘了将记录y坐标的isRecord改为false,以便于下一次手势的执行 isRecord = false; break; } } } return super.onTouchEvent(ev); } private Animation animation; /** * 根据状态改变headerView的动画和文字显示 * @param state */ private void changeHeaderByState(int state){ switch (state) { case DONE://如果的隐藏的状态 //设置headerView的padding为隐藏 headerView.setPadding(0, -headerViewHeight, 0, 0); //第一状态的view显示出来 mFirstView.setVisibility(View.VISIBLE); imageView_B.setVisibility(VISIBLE); tv_pull_to_refresh.setText("下拉刷新"); //第二状态的view隐藏起来 mSecondView.setVisibility(View.GONE); //停止第二状态的动画 secondAnim.stop(); //第三状态的view隐藏起来 mThirdView.setVisibility(View.GONE); //停止第三状态的动画 thirdAnim.stop(); break; case RELEASE_TO_REFRESH://当前状态为放开刷新 //文字显示为放开刷新 tv_pull_to_refresh.setText("放开刷新"); //第一状态view隐藏起来 mFirstView.setVisibility(View.GONE); //第二状态view显示出来 mSecondView.setVisibility(View.VISIBLE); //播放第二状态的动画 secondAnim.start(); //第三状态view隐藏起来 mThirdView.setVisibility(View.GONE); //停止第三状态的动画 thirdAnim.stop(); break; case PULL_TO_REFRESH://当前状态为下拉刷新 imageView_B.setVisibility(VISIBLE); //设置文字为下拉刷新 tv_pull_to_refresh.setText("下拉刷新"); //第一状态view显示出来 mFirstView.setVisibility(View.VISIBLE); //第二状态view隐藏起来 mSecondView.setVisibility(View.GONE); //第二状态动画停止 secondAnim.stop(); //第三状态view隐藏起来 mThirdView.setVisibility(View.GONE); //第三状态动画停止 thirdAnim.stop(); break; case REFRESHING://当前状态为正在刷新 //文字设置为正在刷新 tv_pull_to_refresh.setText("正在刷新"); //第一状态view隐藏起来 mFirstView.setVisibility(View.GONE); //第三状态view显示出来 mThirdView.setVisibility(View.VISIBLE); //第二状态view隐藏起来 mSecondView.setVisibility(View.GONE); //停止第二状态动画 secondAnim.stop(); //启动第三状态view thirdAnim.start(); imageView_B.setVisibility(GONE); animation = new TranslateAnimation(0, 0, 0, 600); animation.setDuration(3000); imageViewBack.setAnimation(animation); break; default: break; } } private void measureView(View child) { ViewGroup.LayoutParams p = child.getLayoutParams(); if (p == null) { p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); } int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width); int lpHeight = p.height; int childHeightSpec; if (lpHeight > 0) { childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY); } else { childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); } child.measure(childWidthSpec, childHeightSpec); } }

github代码:

项目代码下载(https://github.com/molu0007/IBU_ListView)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

时间: 2024-09-15 16:56:05

Android自定义渐变式炫酷ListView下拉刷新动画的相关文章

Android自定义控件开发实战之实现ListView下拉刷新实例代码_Android

这篇博客为大家介绍一个android常见的功能--ListView下拉刷新: 首先下拉未松手时候手机显示这样的界面: 下面的代码是自定的扎样的控件: <span style="font-family: comic sans ms,sans-serif; font-size: 16px;">package com.dhsr.smartID.view; import android.content.Context; import android.util.AttributeSe

Android自定义控件开发实战之实现ListView下拉刷新实例代码

这篇博客为大家介绍一个android常见的功能--ListView下拉刷新: 首先下拉未松手时候手机显示这样的界面: 下面的代码是自定的扎样的控件: <span style="font-family: comic sans ms,sans-serif; font-size: 16px;">package com.dhsr.smartID.view; import android.content.Context; import android.util.AttributeSe

Android仿新浪微博自定义ListView下拉刷新(4)_Android

自定义PullToRefreshListView继承ListView,在ListView头部添加一个下拉的头部布局.跟ListView用法完全一致. 该自定义Listview代码详解具体可参考: http://www.jb51.net/article/97845.htm 此处详细介绍Adapter的详细代码. 1.首先给Adapter绑定ListView布局. 2.其次创建一个层次对应组件的类,将对应的组件和对象进行关联,提高效率. 3.然后跟陆获得的图片路径异步下载图片,由于不知道该微博图片的

Android使用PullToRefresh完成ListView下拉刷新和左滑删除功能_Android

ListView下刷新刷功能相信从事Android开发的猿友们并不陌生,包括现在Google亲儿子SwipeRefreshLayout实现效果在一些APP上也能看见(不过个人不喜欢官方的刷新效果).本文就带领一些刚入门android的朋友或者一起爱分享的朋友来简单的实现ListView的下拉刷新和左滑删除效果. 一.本文主要内容: 使用PullToRefresh完成ListView下拉.上拉刷新: 扩展PullToRefresh完美的实现ListView左滑删除效果: 注意:本文中的PullTo

Android程序开发之Listview下拉刷新上拉(滑动分页)加载更多_Android

最近做的类似于微博的项目中,有个Android功能要使用到listview的向下拉刷新来刷新最新消息,向上拉刷新(滑动分页)来加载更多. 新浪微博就是使用这种方式的典型. 当用户从网络上读取微博的时候,如果一下子全部加载用户未读的微博这将耗费比较长的时间,造成不好的用户体验,同时一屏的内容也不足以显示如此多的内容.这时候,我们就需要用到另一个功能,那就是listview的分页了,其实这个分页可以做成客户端的分页,也可以做成服务器端的分页(点击加载时,从服务器对应的加载第N页就好了!!!).通过分

Android ListView下拉刷新上拉自动加载更多DEMO示例_Android

代码下载地址已经更新.因为代码很久没更新,已经很落伍了,建议大家使用RecyclerView实现. 参考项目: https://github.com/bingoogolapple/BGARefreshLayout-Android https://github.com/baoyongzhang/android-PullRefreshLayout 下拉刷新,Android中非常普遍的功能.为了方便便重写的ListView来实现下拉刷新,同时添加了上拉自动加载更多的功能.设计最初是参考开源中国的And

Android中ListView下拉刷新的实现方法实例分析_Android

本文实例讲述了Android中ListView下拉刷新的实现方法.分享给大家供大家参考,具体如下: ListView中的下拉刷新是非常常见的,也是经常使用的,看到有很多同学想要,那我就整理一下,供大家参考.那我就不解释,直接上代码了. 这里需要自己重写一下ListView,重写代码如下: package net.loonggg.listview; import java.util.Date; import android.content.Context; import android.util.

Android中ListView下拉刷新的实现方法_Android

ListView中的下拉刷新是非常常见的,也是经常使用的,看到有很多同学想要,那我就整理一下,供大家参考.那我就不解释,直接上代码了. 这里需要自己重写一下ListView,重写代码如下: package net.loonggg.listview; import java.util.Date; import android.content.Context; import android.util.AttributeSet; import android.view.LayoutInflater;

Android中ListView下拉刷新的实现代码

Android中ListView下拉刷新 实现效果图: ListView中的下拉刷新是非常常见的,也是经常使用的,看到有很多同学想要,那我就整理一下,供大家参考.那我就不解释,直接上代码了. 这里需要自己重写一下ListView,重写代码如下: package net.loonggg.listview; import java.util.Date; import android.content.Context; import android.util.AttributeSet; import a