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

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

主要要点

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

效果图

95461d3fef08a5504e36f9239da98a0b.gif

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代码:

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值