仿天天动态上拉播放界面控件

来源:互联网 发布:免费漫画阅读软件 编辑:程序博客网 时间:2024/09/21 09:03

看到天天动听的播放界面,可以从底部划出来,被其效果惊艳到,于是想自己动手模仿。

                               



                               

效果:1,在Content未展开的状态(隐藏):

                  1>点击Handler控件,弹出Content。

          2>拖动Handler,Content会从底部逐渐出来。

           2,在Content展开的状态:

拖动Content,content位置随着手指的滑动而产生位置变化。


最开始想到的是用SlidingDraw,因为有几分相似,SlidingDraw有一个handle,拖着handle让content跟着移动。

区别在于在我们要设计的控件handle是不动的,监听到handle的touch事件,只能让content去移动。

要自定义一个控件,首先一定要清楚一下几个方法,onMeasure(),用于测量view的大小,onLayout()用于放置view的位置,onDraw()用于绘制控件,onDispatchDraw()一般在这里绘制子控件。这里我们把handle放在最底部,content位于handle下面,也就是屏幕外面。


实现思路:

1,Content关闭状态,touch事件的监听应该在Handler上,也就是说父控件不能去拦截,在onInterceptTouchEvent()中返回false,handler控件去消费onTouch事件。这里用了一个手势辅助类GestureDetector,其实我们要用到只是滑动手势和点击,所以这里不用这个辅助类也可以自己实现。

2,Content展开状态,touch事件的监听应该放在ParentView上,也就是说监听事件是全屏的。(一开始我犯了一个错误,将监听事件放到content上,也就是content去监听滑动,然后移动自己,这样会由于移动content自身后,监听位置更新不及时而发生抖动现象)。

3,当拖动content到屏幕中间而放手,应该去调整content的位置,播放从当前位置到展开位置或者关闭位置的动画。



由于代码比较简单,关于自定义控件的事件监听以及重要的几个方法这里不多啰嗦了。 

SlidingPanel.java

package com.example.huwei.slidingpaneldemo.ui;import android.content.Context;import android.graphics.Canvas;import android.graphics.Rect;import android.os.Handler;import android.util.AttributeSet;import android.util.Log;import android.view.GestureDetector;import android.view.Gravity;import android.view.MotionEvent;import android.view.View;import android.view.animation.AccelerateInterpolator;import android.view.animation.Animation;import android.view.animation.TranslateAnimation;import android.widget.LinearLayout;import android.widget.Scroller;import com.example.huwei.slidingpaneldemo.R;/** * Created by huwei on 14-12-19. */public class SlidingPanel extends LinearLayout implements GestureDetector.OnGestureListener {    private static final String TAG = "SlidingPanel";    private static final String GTAG = "GTAG";    //手势TAG    private View mHandle;    private View mContent;    private int mContentRangeTop;   //content在父布局的移动范围    private int mContentRangeBottom;    private int mDownY;     //ACTION_DOWN时y的坐标    private boolean mExpanded=false;  //是否展开    private static final int ANIMATION_DURATION = 1000;   //  从底部到上面需要1s    private GestureDetector mGestureDetector;   //检测手势辅助类    public SlidingPanel(Context context) {        this(context, null);    }    public SlidingPanel(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public SlidingPanel(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        mGestureDetector = new GestureDetector(context, this);        setOrientation(LinearLayout.VERTICAL);    }    @Override    protected void onFinishInflate() {        mHandle = findViewById(R.id.handle);        if (mHandle == null) {            throw new IllegalArgumentException("The handle attribute is required and must refer "                    + "to a valid child.");        }        mContent =  findViewById(R.id.content);        if (mContent == null) {            throw new IllegalArgumentException("The content attribute is required and must refer "                    + "to a valid child.");        }        Log.i(TAG, "***********handle:" + mHandle + "************content:" + mContent + "**********");                mHandle.setClickable(true);        mHandle.setOnTouchListener(touchListener);    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);        int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);        View handle = mHandle;        measureChild(handle, widthMeasureSpec, heightMeasureSpec);        int height = (int) heightSpecSize;        measureChild(mContent, MeasureSpec.makeMeasureSpec(widthSpecSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));        setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);    }    @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {        super.onLayout(changed, l, t, r, b);        //获取自身的宽高        final int width = r - l;        final int height = b - t;        mContentRangeTop=0;        mContentRangeBottom = b - t;        final View handle = mHandle;        int childHeight = handle.getMeasuredHeight();        int childWidth = handle.getMeasuredWidth();        handle.layout(0, height - childHeight, childWidth, height);        final View content = mContent;        if (!mExpanded) {            mContent.layout(0, mContentRangeBottom, content.getMeasuredWidth(), mContentRangeBottom + content.getMeasuredHeight());        } else {            mContent.layout(0, mContentRangeTop, content.getMeasuredWidth(), mContentRangeTop + content.getMeasuredHeight());        }    }    @Override    protected void dispatchDraw(Canvas canvas) {        super.dispatchDraw(canvas);        long drawingTime = getDrawingTime();        final View handle = mHandle;        drawChild(canvas, handle, drawingTime);        final View content = mContent;        drawChild(canvas, content, drawingTime);    }    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        return mExpanded;    }    @Override    public boolean onTouchEvent(MotionEvent event) {        switch (event.getAction()){            case MotionEvent.ACTION_DOWN:                mDownY= (int)event.getY();                break;            case MotionEvent.ACTION_MOVE:                int nowY=(int)event.getY();                                moveContent(nowY-mDownY);                break;            case MotionEvent.ACTION_UP:                adjustContentView();                break;        }        return  mExpanded;    }     /**     * 停止滑动     *     * @param     */    private void stopTracking() {        //判断content是展开还是收缩        updateExpanded();    }    /**     * 更新mExpanded状态     */    private void updateExpanded(){        if (mContent.getTop() <= mContentRangeTop) {            mExpanded = true;        } else {            mExpanded = false;        }    }    /**     * move content到指定位置     *     * @param position     */    private void moveContent(int position) {        Log.i(GTAG, "*********move Content:position" + position + "**********");        //不能移出上边界        if (position < mContentRangeTop) {            position = mContentRangeTop;        } else if (position > mContentRangeBottom) {            position = mContentRangeBottom;        }        final View content=mContent;        final int top = (int) mContent.getY();        final int deltaY = position - top;        content.layout(0,position,content.getWidth(),position+content.getHeight());    }    //移动Content    private void doAnimation(int nowY, final int targetY) {        AccelerateInterpolator accelerateInterpolator = new AccelerateInterpolator();        //BounceInterpolator bounceInterpolator=new BounceInterpolator();        TranslateAnimation animation = new TranslateAnimation(0, 0, 0, targetY - nowY);        animation.setDuration(ANIMATION_DURATION * Math.abs(targetY - nowY) / mContentRangeBottom);        animation.setInterpolator(accelerateInterpolator);        animation.setAnimationListener(new Animation.AnimationListener() {            @Override            public void onAnimationStart(Animation animation) {            }            @Override            public void onAnimationEnd(Animation animation) {                //Log.i(TAG,"onAnimationEnd");                mContent.clearAnimation();                mContent.layout(0, targetY, mContent.getMeasuredWidth(), targetY + mContent.getMeasuredHeight());                stopTracking();            }            @Override            public void onAnimationRepeat(Animation animation) {            }        });        mContent.startAnimation(animation);    }    /**     * 点击时打开Content*     */    private void open() {        doAnimation(mContentRangeBottom, 0);        stopTracking();    }    /**     * ACTION_UP时 contentView不是停靠在屏幕边缘(在屏幕中间)时,调整contentView的位置*     */    private void adjustContentView(){        final int top = mContent.getTop();        //切割父容器,分成3等份        final int perRange=(mContentRangeBottom-mContentRangeTop)/3;        if(mExpanded){            //小于1/3            if(top<perRange+mContentRangeTop){                doAnimation(top,0);            }else{                doAnimation(top, mContentRangeBottom);            }        }else{            //小于2/3            if(top<mContentRangeTop+perRange*2){                doAnimation(top,0);            }else{                doAnimation(top,mContentRangeBottom);            }        }            }    /**     *按下时触发*      * @param e     * @return     */    @Override    public boolean onDown(MotionEvent e) {        Log.i(GTAG, "onDown:"+e.getY());        return false;    }    @Override    public void onShowPress(MotionEvent e) {        Log.i(GTAG, "onShowPress");    }    /**     * 轻轻点击*      * @param e     * @return     */    @Override    public boolean onSingleTapUp(MotionEvent e) {        Log.i(GTAG, "onSingleTapUp");        if (!mExpanded) {            open();        }        return false;    }    /**     * 滚动时出发*      * @param e1     * @param e2     * @param distanceX     * @param distanceY     * @return     */    @Override    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {        int touchY = (int) e2.getY();        Log.i(GTAG, "onScroll:"+mContent.getY());        moveContent(touchY - mDownY + (mExpanded ? mContentRangeTop : mContentRangeBottom));        return false;    }    /**     * 长按*      * @param e     */    @Override    public void onLongPress(MotionEvent e) {        Log.i(GTAG, "onLongPress");    }    /**     * 瞬时滑动*     * @param e1     * @param e2     * @param velocityX     * @param velocityY     * @return     */    @Override    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {        Log.i(GTAG, "onFling");        return false;    }    OnTouchListener touchListener = new OnTouchListener() {        @Override        public boolean onTouch(View v, MotionEvent event) {            final View handle = mHandle;            if (event.getAction() == MotionEvent.ACTION_DOWN) {                final int top = handle.getTop();                mDownY = (int) event.getY();                Log.i(GTAG,"mDownY:"+mDownY);            } else if (event.getAction() == MotionEvent.ACTION_UP) {                 adjustContentView();            }            Log.i(GTAG, "onTouch:" + event.getAction() + " y:" + event.getY());            return mGestureDetector.onTouchEvent(event);        }    };}

xml

<com.example.huwei.slidingpaneldemo.ui.SlidingPanel xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent">    <Button        android:layout_width="wrap_content"        android:layout_height="wrap_content" />    <Button        android:layout_width="wrap_content"        android:layout_height="wrap_content" />    <LinearLayout        android:id="@+id/handle"        android:orientation="horizontal"        android:layout_width="fill_parent"        android:layout_height="68dp"        android:background="@drawable/handle_seletor">        <Button            android:layout_width="wrap_content"            android:layout_height="wrap_content" />        </LinearLayout>    <LinearLayout        android:orientation="vertical"        android:id="@+id/content"        android:background="#78ADFF2F"        android:layout_width="match_parent"        android:layout_height="match_parent" >        <Button             android:layout_width="wrap_content"            android:layout_height="wrap_content"/>    </LinearLayout></com.example.huwei.slidingpaneldemo.ui.SlidingPanel>

百度网盘地址

csdn下载


0 0
原创粉丝点击