Android自定义View之(PullDoorView)

已经坚持写blog一段时间了,干什么事都需要恒心,虽然我的博客浏览量很少,但如果我能把自己所学的总结一遍的话,对于自己也是一个不小的收获,所以,骚年,加油吧!
本项目的github地址:项目链接地址
我们今天要实现的叫PullDoorView,有点类似抽屉的感觉,一些splash界面,或者一些特定的场合会用得到,不管用不用得到,我们主要是了解其实现原理就ok了。没有找到什么好的录屏工具,控件随着手的滑动而移动,当手放开的时候,如果滑动超过控件的一般,那么久自动打开,反正自动关闭,先看看效果图:
没找到好的录屏软件,求推荐

实现思路:自定义view,通过监听View的滑动事件,然后调用View的scrollto方法移动子view的位置,监听ACTION_UP操作,当滑动的位置大于控件的一半的时候调用scroller的startScroller方法,开始自动移动子view的位置。
好了,咱们直接上代码了

第一步:创建一个View继承ViewGroup,然后覆盖三个构造方法(自定义view的老套路了)
这里我们就直接继承一个FramLayout了

**
 * Author:Yqy
 * Date:2016-08-03
 * Desc:拉伸开门View
 * Company:cisetech
 */
public class PullDoorView extends FrameLayout{
 public PullDoorView(Context context) {
        this(context, null);
    }

    public PullDoorView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public PullDoorView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setUpView();
    }
}

第二步:初始化一些操作,创建一个Scroller,在Framlayout底部放一个ImageView,然后放上我们自己的一张图片,放一个TextView在ImageView的上面,并靠父控件的底部,用来提示“上拉消失的提示”

 /**
     * 初始化View
     */
    private void setUpView() {
        /**
         * 创建一个带BounceInterpolator插值器(结束时候前后跳动)
         * 的Scroller
         */
        mInterpolator=new BounceInterpolator();
        mScroller=new Scroller(getContext(),mInterpolator);
        /**
         * 创建一个ImageView放置父控件
         */
        ImageView imageView=new ImageView(getContext());
        FrameLayout.LayoutParams imgLp=new FrameLayout.LayoutParams(-1,-1);
        imageView.setImageResource(R.mipmap.ic_introduction);
        imageView.setScaleType(ImageView.ScaleType.FIT_XY);
        addView(imageView, imgLp);
        /**
         * 创建一个TextView,放置控件底部
         */
        FrameLayout.LayoutParams textLp=new FrameLayout.LayoutParams(-2,-2);
        textLp.gravity= Gravity.CENTER_HORIZONTAL|Gravity.BOTTOM;
        TextView textView=new TextView(getContext());
        textView.setText("向上滑动关闭此广告");
        textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14.5f);
        textView.setTextColor(Color.DKGRAY);
        textView.setLayoutParams(textLp);
        addView(textView);
        /**
         * 创建一个alpha动画
         */
        AlphaAnimation a=new AlphaAnimation(0,1f);
        a.setDuration(1000);
        a.setRepeatCount(Animation.INFINITE);
        a.setRepeatMode(Animation.REVERSE);
        textView.startAnimation(a);
    }

第三步:根据手指滑动的距离调用View的scrollTo方法,移动子View

private float lastX,lastY;
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action=event.getAction();
        /**
         * 计算距离差
         */
        int durationY= (int) (event.getY()-lastY);
        switch (action){
            case MotionEvent.ACTION_DOWN:
                /**
                 * 记录按下的位置
                 */
                lastX=event.getX();
                lastY=event.getY();
                if(!mScroller.isFinished()){
                    mScroller.abortAnimation();
                }
                scrollTo(0, 0);//关闭
                return true;
            case MotionEvent.ACTION_MOVE:
                /**
                 * 只处理向上滑
                 */
                if(durationY<0){
                    scrollBy(0, -(int) durationY);
                }
                lastX=event.getX();
                lastY=event.getY();
                break;
            case MotionEvent.ACTION_UP:
                if(getScrollY()>=getHeight()/2){//当滑动到控件一半的时候自动上滑打开控件
                    mScroller.startScroll(0, getScrollY(),0,getHeight(),500);
                }else{//滑动小于一般,自动下滑回到原位
                    mScroller.startScroll(0, getScrollY(),0,-getScrollY(),500);
                }
                /**
                 * 记得去重新绘制一下
                 */
                invalidate();
                break;
        }
        return super.onTouchEvent(event);
    }

第四步:也是最关键的一步,调用Scroller的startScroller自动滑动,然后复写View的computeScroll方法重绘制View

/**
     * 当控件不断滑动的时候会回调此方法
     */
    @Override
    public void computeScroll() {
        super.computeScroll();
        if(mScroller.computeScrollOffset()){//判断是否在自动滑动中
            int currY = mScroller.getCurrY();
            scrollTo(0,currY);
            invalidate();//一定要记得重新绘制View哦
        }
    }
  case MotionEvent.ACTION_UP:
                if(getScrollY()>=getHeight()/2){//当滑动到控件一半的时候自动上滑打开控件
                    mScroller.startScroll(0, getScrollY(),0,getHeight(),500);
                }else{//滑动小于一般,自动下滑回到原位
                    mScroller.startScroll(0, getScrollY(),0,-getScrollY(),500);
                }
                /**
                 * 记得去重新绘制一下
                 */
                invalidate();
                break;
        }

第五步:测试一下效果
layout文件:

<?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.cisetech.customer.pulldoorview.MainActivity">

    <com.cisetech.customer.pulldoorview.PullDoorView
        android:background="#ffff00"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
         />
</RelativeLayout>

总结:
至于Scroller的其他一些用法,大家baidu一下或者是查看一下api文档都有写的,坚持坚持!!!!一定会有收获的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值