Android之---PullRefreshListView(带抖动效果的下拉刷新)

PullRefreshListView(带抖动效果的下拉刷新)

效果图

这里写图片描述

代码实现

1.首先实现下拉抖动的自定义的view(可以是铃铛、锣鼓啊什么的图片)

ScaleView.java:

package com.xiaokele.pullrefreshlistview;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.View;

/**
 *
 * 自定义的缩放的View
 */
public class ScaleView extends View {
    private Bitmap initBitmap;
    private Bitmap scaleBitmap;
    private float mCurrentProgress = 1;
    private int mWidth;
    private int mHeight;

    public ScaleView(Context context) {
        super(context);
        init(context);
    }

    public ScaleView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public ScaleView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context context) {
        initBitmap = Bitmap.createBitmap(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher));
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        if (widthMode == MeasureSpec.EXACTLY) {
            mWidth = widthSize;
        } else {
            mWidth = initBitmap.getWidth();
        }

        if (heightMode == MeasureSpec.EXACTLY) {
            mHeight = heightSize;
        } else {
            mHeight = initBitmap.getHeight();
        }

        setMeasuredDimension(mWidth, mHeight);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //考虑padding的影响
        int leftPadding = getPaddingLeft();
        int topPadding = getPaddingTop();
        int rightPadding = getPaddingRight();
        int bottomPadding = getPaddingBottom();

        int lastWidth = getMeasuredWidth() - leftPadding - rightPadding;
        int lastHeight = getMeasuredHeight() - topPadding - bottomPadding;

        scaleBitmap = Bitmap.createScaledBitmap(initBitmap, lastWidth, lastHeight, true);

        canvas.save();
        //缩放画布
        canvas.scale(mCurrentProgress, mCurrentProgress, lastWidth / 2 + leftPadding, lastHeight / 2 + topPadding);
        //缩放图形,要写在画布缩放后边
        canvas.drawBitmap(scaleBitmap, topPadding, leftPadding, null);

        canvas.restore();
    }

    public void setCurrentProgress(float currentProgress) {
        mCurrentProgress = currentProgress;
        postInvalidate();
    }
}
2.接下来是实现自定义的带下拉效果的ListView(PullRefreshListView)

添加的HeaderView布局sample_pull_refresh_list_view.xml如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:gravity="center"
    android:orientation="horizontal"
    android:layout_height="match_parent">

    <com.xiaokele.pullrefreshlistview.ScaleView
        android:id="@+id/scaleView"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:layout_marginBottom="5dp"
        android:layout_marginTop="5dp" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:gravity="center"
        android:text="下拉刷新"
        android:textColor="@android:color/black"
        android:textSize="16sp" />

</LinearLayout>

PullRefreshListView.java如下:

package com.xiaokele.pullrefreshlistview;

import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
import android.widget.AbsListView;
import android.widget.ListView;
import android.widget.TextView;

/**
 * TODO: document your custom view class.
 */
public class PullRefreshListView extends ListView implements AbsListView.OnScrollListener {
    private ScaleView scaleView;
    private TextView textView;
    private View mHeadView;
    private int mHeadViewHeight;
    private float mLastY, y, offsetY;
    private int mfirstVisibleItem;
    /**
     * 动画播放时间
     */
    private static final int ANIM_DURATION = 200;
    /**
     * 缩小滑动时对padding的影响
     */
    private static final int RESISTANCE = 3;
    /**
     * 是否实现下拉刷新接口
     */
    private boolean refreshEnable = false;
    /**
     * 是否在播放动画
     */
    private boolean isAnimatoring = false;
    /**
     * 下拉刷新回调接口
     */
    private OnPullRefreshListener mOnPullRefreshListener;
    /**
     * 刷新动画
     */
    private ObjectAnimator mObjectAnimator;

    public PullRefreshListView(Context context) {
        super(context);
        init(context);
    }

    public PullRefreshListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public PullRefreshListView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context context) {
        setOverScrollMode(OVER_SCROLL_NEVER);

        //先把布局加载进来(**就是上面的sample_pull_refresh_list_view.xml**)
        mHeadView = LayoutInflater.from(context).inflate(R.layout.sample_pull_refresh_list_view, null, false);
        scaleView = (ScaleView) mHeadView.findViewById(R.id.scaleView);
        textView = (TextView) mHeadView.findViewById(R.id.textView);
        addHeaderView(mHeadView);

        super.post(new Runnable() {
            @Override
            public void run() {
                //把headView的高度取出来
                mHeadViewHeight = mHeadView.getMeasuredHeight();
                resetState();
            }
        });
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        if (!refreshEnable || isAnimatoring) {
            return super.onTouchEvent(ev);
        }

        y = ev.getY();
        switch (ev.getAction()) {
            case MotionEvent.ACTION_MOVE:
                //下拉,最多下拉到2倍高度的位置
                if (mfirstVisibleItem == 0 && y > mLastY && offsetY < 2 * mHeadViewHeight) {
                    changState();
                }
                //上滑
                if (mfirstVisibleItem == 0 && y < mLastY && offsetY > 0) {
                    changState();
                }
                break;
            case MotionEvent.ACTION_UP:
                int curPaddingTop = getPaddingTop();

                if (curPaddingTop > 0) {
                    isAnimatoring = true;

                    refreshingState();

                    mObjectAnimator = startRefreshAnim(scaleView);
                    post(new Runnable() {
                        @Override
                        public void run() {
                            mOnPullRefreshListener.onRefresh();
                        }
                    });
                } else {
                    resetState();
                }
                break;
        }
        mLastY = y;
        return super.onTouchEvent(ev);
    }

    /**
     * 正在刷新的状态
     */
    private void refreshingState() {
        setHeadViewPadding(mHeadViewHeight);
        setCurrentProgress(mHeadViewHeight);
        offsetY = mHeadViewHeight;
        textView.setText("正在刷新");
    }

    /**
     * 将状态设置回原始状态
     */
    private void resetState() {
        offsetY = 0;
        setHeadViewPadding(0);
        setCurrentProgress(0);
    }

    /**
     * 滑动时动态设置各个组件的状态
     */
    private void changState() {
        offsetY = offsetY + (y - mLastY) / RESISTANCE;
        setHeadViewPadding((int) (offsetY));
        //从二分之一的地方开始缩放,使缩放效果更明显
        if (offsetY > mHeadViewHeight / 2) {
            setCurrentProgress((offsetY - mHeadViewHeight / 2) * 2);
        }
        //设置字体状态
        if (offsetY > mHeadViewHeight) {
            textView.setText("松开刷新");
        } else {
            textView.setText("下拉刷新");
        }
    }

    /**
     * 播放刷新动画
     *
     * @param target
     */
    private ObjectAnimator startRefreshAnim(ScaleView target) {
        ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(target, View.TRANSLATION_X, 0, 20, 0, -20, 0);
        objectAnimator.setRepeatCount(ValueAnimator.INFINITE);
        objectAnimator.setInterpolator(new DecelerateInterpolator());
        objectAnimator.setDuration(ANIM_DURATION);
        objectAnimator.start();
        return objectAnimator;
    }

    /**
     * 根据滑动的距离设置图片的缩放
     *
     * @param offsetY
     */
    private void setCurrentProgress(float offsetY) {
        float scale = offsetY / mHeadViewHeight;
        scale = scale > 1 ? 1 : scale;
        scaleView.setCurrentProgress(scale);
    }

    /**
     * 位移相对于隐藏headview原点
     *
     * @param offset
     */
    private void setHeadViewPadding(int offset) {
        setPadding(0, offset - mHeadViewHeight, 0, 0);
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        mfirstVisibleItem = firstVisibleItem;
    }

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {

    }

    /**
     * 刷新完成
     */
    public void complete() {
        mObjectAnimator.cancel();
        resetState();
        isAnimatoring = false;
    }

    /**
     * 设置刷新回调监听
     *
     * @param onPullRefreshListener
     */
    public void setOnPullRefreshListener(OnPullRefreshListener onPullRefreshListener) {
        if (onPullRefreshListener == null) {
            return;
        }
        this.mOnPullRefreshListener = onPullRefreshListener;
        refreshEnable = true;
    }

    public interface OnPullRefreshListener {
        void onRefresh();
    }
}
3.PullRefreshListView的使用

activity_main.xml如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.xiaokele.pullrefreshlistview.MainActivity">

    <com.xiaokele.pullrefreshlistview.PullRefreshListView
        android:id="@+id/pullRefreshListView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>

MainActivity.java如下:

package com.xiaokele.pullrefreshlistview;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ArrayAdapter;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity implements PullRefreshListView.OnPullRefreshListener {
    private List<String> mDatas;
    private ArrayAdapter<String> mAdapter;
    private PullRefreshListView mPullRefreshListView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        init();
    }

    private void init() {
        try {
            mPullRefreshListView = (PullRefreshListView) findViewById(R.id.pullRefreshListView);
            initData();
            mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mDatas);
            mPullRefreshListView.setOnPullRefreshListener(this);
            mPullRefreshListView.setAdapter(mAdapter);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void initData() {
        mDatas = new ArrayList<>();
        for (int i = 0; i < 20; i++) {
            mDatas.add("xiaokele"+i);
        }
    }

    @Override
    public void onRefresh() {
        Toast.makeText(MainActivity.this, "success", Toast.LENGTH_SHORT).show();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //模拟耗时任务
                    Thread.sleep(3000);

                    MainActivity.this.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            //任务执行完毕
                            mPullRefreshListView.complete();
                        }
                    });

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值