您当前的位置: 首页 > 

xiangzhihong8

暂无认证

  • 4浏览

    0关注

    1324博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

仿美团下拉

xiangzhihong8 发布时间:2015-11-05 10:30:50 ,浏览量:4

git 下载地址:https://github.com/nugongshou110/MeiTuanRefreshListView

这里写图片描述 

实现原理:

美团的下拉刷新分为三个状态:  第一个状态为下拉刷新状态(pull to refresh),在这个状态下是一个绿色的椭圆随着下拉的距离动态改变其大小。  第二个部分为放开刷新状态(release to refresh),在这个状态下是一个帧动画,效果为从躺着变为站起来的动画。  第三个部分为刷新状态(refreshing),在这个状态下也是一个帧动画,是摇头的动画。

第一个状态的实现:

我们的思路是:当前这个椭圆形有一个进度值,这个进度值从0变为1,然后对这个椭圆形进行缩放,我们可以使用自定义View来实现这个效果,我们先来用一个SeekBar来模仿一下下拉距离的进度  这里写图片描述  我们解压美团apk后拿到这张图片:  这里写图片描述

public class MeiTuanRefreshFirstStepView extends View{

    private Bitmap initialBitmap;
    private int measuredWidth;
    private int measuredHeight;
    private Bitmap endBitmap;
    private float mCurrentProgress;
    private Bitmap scaledBitmap;

    public MeiTuanRefreshFirstStepView(Context context, AttributeSet attrs,
            int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

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

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

    private void init(Context context) {
        //这个就是那个椭圆形图片
        initialBitmap = Bitmap.createBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.pull_image));
        //这个是第二个状态娃娃的图片,之所以要这张图片,是因为第二个状态和第三个状态的图片的大小是一致的,而第一阶段
        //椭圆形图片的大小与第二阶段和第三阶段不一致,因此我们需要根据这张图片来决定第一张图片的宽高,来保证
        //第一阶段和第二、三阶段的View的宽高一致
        endBitmap = Bitmap.createBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.pull_end_image_frame_05));
    }

    /**
     * 重写onMeasure方法主要是设置wrap_content时 View的大小
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //根据设置的宽度来计算高度  设置为符合第二阶段娃娃图片的宽高比例
        setMeasuredDimension(measureWidth(widthMeasureSpec),measureWidth(widthMeasureSpec)*endBitmap.getHeight()/endBitmap.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 = endBitmap.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);
        measuredWidth = getMeasuredWidth();
        measuredHeight = getMeasuredHeight();
        //根据第二阶段娃娃宽高  给椭圆形图片进行等比例的缩放
        scaledBitmap = Bitmap.createScaledBitmap(initialBitmap, measuredWidth,measuredWidth*initialBitmap.getHeight()/initialBitmap.getWidth(), true);
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //这个方法是对画布进行缩放,从而达到椭圆形图片的缩放,第一个参数为宽度缩放比例,第二个参数为高度缩放比例,
        canvas.scale(mCurrentProgress, mCurrentProgress, measuredWidth/2, measuredHeight/2);
        //将等比例缩放后的椭圆形画在画布上面
        canvas.drawBitmap(scaledBitmap,0,measuredHeight/4,null);

    }

    /**
     * 设置缩放比例,从0到1  0为最小 1为最大
     * @param currentProgress
     */
    public void setCurrentProgress(float currentProgress){
        mCurrentProgress = currentProgress;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101

然后在Activity里面:

/**
 * Created by zhangqi on 15/11/1.
 */
public class MyActivity extends Activity {
    private MeiTuanRefreshFirstStepView mFirstView;
    private SeekBar mSeekBar;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);
        mSeekBar = (SeekBar) findViewById(R.id.seekbar);
        mFirstView = (MeiTuanRefreshFirstStepView) findViewById(R.id.first_view);
        mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
                //计算出当前seekBar滑动的比例结果为0到1
                float currentProgress = (float) i / (float) seekBar.getMax();
                //给我们的view设置当前进度值
                mFirstView.setCurrentProgress(currentProgress);
                //重画
                mFirstView.postInvalidate();
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {

            }
        });
    }
}
第二个状态的实现:

第二个状态是一个帧动画,我们为了保证View大小的统一,我们也进行自定义View,这个自定义View很简单,只是为了和第一阶段View的宽高保证一致即可

public class MeiTuanRefreshSecondStepView extends View{

    private Bitmap endBitmap;

    public MeiTuanRefreshSecondStepView(Context context, AttributeSet attrs,
            int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

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

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

    private void init() {
        endBitmap = Bitmap.createBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.pull_end_image_frame_05));
    }

    @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;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

我们用xml定义一组帧动画



    
    
    
    
    



  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

帧动画的启动和停止方式:

mSecondView = (MeiTuanRefreshSecondStepView) headerView.findViewById(R.id.second_view);
        mSecondView.setBackgroundResource(R.drawable.pull_to_refresh_second_anim);
        secondAnim = (AnimationDrawable) mSecondView.getBackground();
//启动
secondAnim.start();
//停止
secondAnim.stop();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
第三个状态的实现:

和第二个状态同理,我们也通过自定义View来确保三个状态的View的宽高保持一致

public class MeiTuanRefreshThirdStepView extends View{

    private Bitmap endBitmap;

    public MeiTuanRefreshThirdStepView(Context context, AttributeSet attrs,
            int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

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

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

    private void init() {
        endBitmap = Bitmap.createBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.pull_end_image_frame_05));
    }

    @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;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

我们在xml中定义一组帧动画:



    
    
    
    
    
    
    
    


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

帧动画的启动和停止方式和第二个状态的一样

最后代码请到文章开头去下载
关注
打赏
1482932726
查看更多评论
立即登录/注册

微信扫码登录

0.2747s