手把手教你擼最新Youtube視頻 拖拽動畫效果

前言

又到了金三銀四的季節了,忙的人特別忙,面試啊,加班啊,閒的人也是特別閒吧,就好比我,每天划水,閒的寫文章,作動畫,同時呢各類新技術在不斷的涌進,推進者軟件行業的發展,不要焦慮,不要着急,學好本分,再擴展技能。很少說了,給你們看看作的效果吧。git

github連接根據你們的一致意見開源了github

youtube2.gif

這個是原生的效果
面試

youtube1.gif

這個是作出來的效果bash

動畫分解

動畫分解其實很重要,若是說想模仿一個App的動畫及交互效果,必定要仔細的觀察他在交互細到放慢每個操做,而後在根據這個動態來寫代碼。否則最後實現的效果不同,那豈不是白費了。廢話很少說,上代碼看步驟。ide

第一步視頻原始狀態分析

能夠看到,視頻最初始的狀態是由一個VideoView(能夠是surfaceview都行),加上一個list吧,上下佈局,可是VideoView呢,他是根據視頻尺寸大小動態的調整寬高的,而不是固定的,咱們來分析這個過程佈局

  1. 第一種下拉的時候若是視頻的高度沒有達到原生高度,這時候下面的listview 不能消費touch事件,由videoview來消費這個事件,根據當前的下滑Y值進行調整視頻寬高比
  2. 第二種狀況是若是listview已經滑動了一部分這時候進行下拉,可是viewvideo尚未到達真是高度,這時候touch事件仍是由listview消費,當他滑動到頂部的時候進行攔截touch 而後傳遞給videoview
  3. 第三中狀況,當listview 向下快速滑動的時候會有個慣性的過程,即便手離開手機了 listview仍是在滑動,咱們稱爲慣性滑動,到慣性滑動到頂部的時候,若是視頻高度沒有達到原生高度,這時候要根據這個慣性值來調整調整視頻高度。

第二步 視頻下滑過程分析

由上圖能夠看到當咱們在下拉視頻的時候,視頻的頂部 左右邊距 機listview 都發生改變,同時videoview高度也發生了變化。優化

  1. 下拉的時候margin的 left right top bottom值都在發生改變,videoview 的高度也在發送改變,同時listview 漸漸消失,變成白色的背景,listview的高度在逐漸變小,同時能夠看到在Z軸也發生了改變。可能圖片不清晰,看不出Z軸的變換
  2. 下拉到listview消失的時候,這時候videoview的寬度發生改變,同時控制器出現。這時候videoview寬度仍是在一直的縮小。
  3. 當達到了最小視頻懸浮層的時候,下拉整個視圖愈來愈透明,同時整個佈局在根據手勢在下滑。

第三步 視頻上滑過程分析

上滑過程其實就是把下滑過程反過來而已,這裏我就再也不過多追溯了。動畫

擼代碼

主要的邏輯在上面都有,下面我就簡單的對上面的邏輯進行分析一下,總體代碼想要的老鐵私信我留言都行ui

如何對listview和videoview進行touch的分發

這裏我使用的是一個LinearLayout做爲父佈局進行組裝這兩個子view,而後根據viewgroup的dispatchTouchEvent方法裏面加判斷進行事件的分發。網上這些代碼不少我就不詳細贅述了,其實我這裏仍是有不少能夠優化的地方,這只是個demo。spa

  • 和上面動畫分解的邏輯一致,一看videoview 是否達到最大值,listview是否在頂部。
  • listview(我這邊用的時候recyclerview都同樣)是否在頂部能夠經過調用addOnScrollListener()來判斷是不是第一個可見的item *判斷videoview是否達到最大值呢,根據視頻的寬高來。能夠經過Mediaplayer來獲取,
//分發recyclerview和videoview事件
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        y = ev.getY();
        int pointerId = ev.getPointerId(0);
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mDownY = ev.getY();
                Log.i(TAG, "dispatchTouchEvent: ACTION_DOWN " + mDownY);
                if (mVelocityTracker == null) {
                    mVelocityTracker = VelocityTracker.obtain();
                } else {
                    mVelocityTracker.clear();
                }
                mVelocityTracker.addMovement(ev);
                break;
            case MotionEvent.ACTION_MOVE:

                float dDownY = y - mDownY;

                Log.i(TAG, "dispatchTouchEvent: " + mDownY + " " + y);
                mVelocityTracker.addMovement(ev);
                mVelocityTracker.computeCurrentVelocity(1000);


                if ((mDownY >= (layoutPVideo.getHeight() + layoutPVideo.getMarginTop())) && dDownY > 0 && layoutPVideo.getHeight() < originalHeight + 600 && (isList2Top)) {
                    //判斷點擊的範圍,及當前視頻尺寸大小。listview是否已經滑到頂部

                    layoutPVideo.setHeight((int) (layoutPVideo.getHeight() + dDownY));
                    Log.i(TAG, "dispatchTouchEvent: xia " + dDownY);
                    mDownY = y;
                    return true;
                } else if ((mDownY >= (layoutPVideo.getHeight() + layoutPVideo.getMarginTop())) && dDownY <= 0 && layoutPVideo.getHeight() >= originalHeight) {
                    //調整視頻view 高度
                    layoutPVideo.setHeight((int) (layoutPVideo.getHeight() + dDownY));
                    //能夠加個彈性動畫顯得更流暢
                    Log.i(TAG, "dispatchTouchEvent: shang " + dDownY);
                    mDownY = y;
                    return true;
                }
                break;
            case MotionEvent.ACTION_UP:
                float yVelocity = VelocityTrackerCompat.getYVelocity(mVelocityTracker,
                        pointerId);
                Log.i("VelocityTrackerCompat", "Y velocity: " +
                        yVelocity);
                
                if (yVelocity >= 5685 && layoutPVideo.getHeight() < originalHeight + 600) {
                    //判斷慣性加速度根據慣性加速度進行引導視頻大小到底部
                    headMoveToMax();
                } else {
                    Log.i(TAG, "headMoveToMax: not come in" + " " + (layoutPVideo.getHeight() < originalHeight + 600));
                }
                break;
            case MotionEvent.ACTION_CANCEL:
                mVelocityTracker.recycle();
                break;
        }


        return super.dispatchTouchEvent(ev);
    }

複製代碼

如何動態的跳轉左右邊距及視頻寬高

這裏我用了一個包裝類拿到當前view的layoutParams,而後經過touchEvent 拿到滑動的值來動態的修改當前view 的寬高和margin值,這個代碼我就補貼了,就是set get方法。

  • 第一步下滑調整margin的左右上下,及videoview 的高度。
  • 第二步繼續下滑調整videoview的寬度
  • 第三步下滑隱藏總體view
private void updateVideoView(int m, int originY) {

        canHide = false;
        if (mDetailView.getHeight() == 0) {
            if (layoutPVideoView.getMarginRight() <= videoWidthPx && 0 < originY) {


                int value = layoutPVideoView.getMarginRight() + originY * 9;//加速縮小
                if (value > videoWidthPx) {
                    value = (int) videoWidthPx;
                }
                float percent = (videoWidthPx - value) / videoWidthPx;
                if (0 > percent) {
                    percent = 0.f;
                }
                int videoHeight = (int) (videoMinHeightPx * (1 - percent));
                int videoMTop = (int) (allMinScrollY * (1 - percent));
                layoutPVideo.setMarginTop((int) (allScrollY + videoMTop));
                layoutPVideo.setHeight((int) (videoHeightPx - videoHeight));
                layoutPVideoView.setMarginRight(value);



                canHide = true;
                Log.i(TAG, "updateVideoView: "+isBottomMax);
                if (layoutPVideoView.getMarginRight() >= videoWidthPx) {
                    if (isBottomMax) {

                        layoutPVideo.setMarginTop(m);
                        float v = m - (allScrollY + allMinScrollY);
                        mVideoView.setAlpha(1.0f - v / swipePx2Dismiss);

                        if (v >= swipePx2Dismiss) {
                            setVisibility(INVISIBLE);
                            mVideoView.setAlpha(1f);
                        }
                    }
                }

                return;
            }//縮小視頻右邊距


            if (layoutPVideoView.getMarginRight() >= 0 && 0 > originY) {
                int value = layoutPVideoView.getMarginRight() + originY * 9;
//                if (0 > value) {
//                    value = 0;
//                }
                float percent = (videoWidthPx - value) / videoWidthPx;
                if (0 > percent) {
                    percent = 0.f;
                }
                int videoHeight = (int) (videoMinHeightPx * (1 - percent));
                int videoMTop = (int) (allMinScrollY * (1 - percent));
                layoutPVideo.setMarginTop((int) (allScrollY + videoMTop));
                layoutPVideo.setHeight((int) (videoHeightPx - videoHeight));
                layoutPVideoView.setMarginRight(value);
                return;
            }//放大視頻右邊距

            if (layoutPVideoView.getMarginRight() >= 0 && originY > 0) {

                return;
            }//最小化階段


        }


        if (layoutPVideo.getMarginTop() <= 0 && originY < 0) {
            m = 0;
        }//最大化階段

        float percent = (allScrollY - m) / allScrollY;
        if (0 > percent) {
            percent = 0;
            return;

        }

        int videoHeight = (int) (originalHeight - (originalHeight - videoHeightPx) * (1 - percent));
        int listHeight = (int) ((originListHeight) * (percent));
        layoutPVideo.setMarginTop(m);
        layoutPVideo.setHeight(videoHeight);
        layoutPList.setMarginBottom((int) (marginBottomPx * (1 - percent)));
        layoutPList.setHeight(listHeight);
        layoutPCoverView.getView().setAlpha((1 - percent));
        layoutPContainer.setMarginRight((int) (marginRLPx * (1 - percent)));
        layoutPContainer.setMarginLeft((int) (marginRLPx * (1 - percent)));
        int mr = (int) ((1f - percent) * marginPx); //VideoView右邊和詳情View 上方的margin
        layoutPVideo.setZ(mr / 2);//這個是Z軸的值,懸浮效果

    }

複製代碼

ending

花了個把小時寫的東西,但願給老鐵們帶來的是知識的儲備而不是時間的浪費。不早了不早了下班了,想要代碼的老鐵能夠私信 留言都行

相關文章
相關標籤/搜索