Android 高仿騰訊新聞視頻切換效果

是的,你沒看錯,又是騰訊視頻!又是高仿!沒辦法啊,產(傻)品(子)喜歡抄襲別人,天下應用一大抄啊。

我能怎麼辦,我也很絕望啊

仍是上效果圖吧(渣渣千元機,有點卡)

騰訊新聞效果

騰訊
一樣是新聞客戶端,爲何你這麼優秀。

12.jpg
好了,吐槽完畢,看看demo的效果。
高仿效果
跟原效果仍是有點差異的。
畢竟咱們這些開發仔,怎麼跟大佬比呢

拆解一下頁面效果吧:

  • 新聞頁面視頻滾動到屏幕中間自動播放(wifi下,demo沒有判斷)
  • 點擊視頻,頁面切換到視頻列表頁面,期間視頻不會中止播放,平滑過渡到第二個頁面
  • 視頻列表頁面滑動後,播放第一個徹底可見的視頻(我的理解,理解錯了大佬不要打我)
  • 視頻列表頁面,視頻播放時,點擊評論數,切換到評論頁面,效果同上
  • 視頻列表頁面,視頻播放時,點擊其餘item任意區域,該item滑到頂部,並播放視頻

無縫續播這裏不作講解(其實我也不會呀...),作過播放器的應該都懂吧,原理大體就是:git

解碼器動態關聯不一樣的渲染視圖(RenderView),好比使用MediaPlayer動態關聯SurfaceView,就如同一個電腦主機不斷鏈接不一樣的顯示器。
複製代碼

PS:這裏注意一下,render不要重置,否則會閃屏哦github

Demo中用的是這個播放器 PlayerBase,高度解耦(不像其餘播放器同樣,對佈局文件有限制),支持各類自定義,最大的好處的就是提供能無縫續播助手(續播的話不要使用mediaPlayer,會出現問題)。 bash

美滋滋

播放器相關

這裏仍是簡單說下播放器怎麼用吧,不須要改界面的話(demo中略微作了修改),直接拷下面紅色方框中的類,在Application裏面進行配置就可使用啦(ijk,exo須要引入對應的庫哦,demo中ijk不支持https,因此視頻可能不能播放)。 網絡

無縫續播相關都在 RelationAssist類裏。續播的話直接調用

AssistPlayer.get().play(mContainer, null);
複製代碼

就能夠在不一樣的容器內(即上面的mContainer)繼續播放以前的內容了。 須要自定義界面或者有其餘問題的參考這裏demo,有問題的加羣問羣主吧。ide

新聞列表頁

用RecyclerView實現,這裏說一下頁面滑動對視頻item的處理:當頁面中止滑動後,判斷是屏幕中央是否有可見的視頻item,有則開始播放。同時,判斷以前是否有在播放的視頻滑出了界面,有則中止播放。佈局

//僞代碼
if (newState == SCROLL_STATE_IDLE) {
            //滑動屏幕中間開始
            LinearLayoutManager manager = (LinearLayoutManager) recyclerView.getLayoutManager();
            int first = manager.findFirstVisibleItemPosition();
            int last = manager.findLastVisibleItemPosition();
            for (int i = first; i <= last; i++) {
                if (isVideo) {
                    //列表視頻
                    if (isCenter && !AssistPlayer.get().isPlaying()) {
                        ImageView imageView = view.findViewById(R.id.adapter_video_image);
                        imageView.performClick();
                        break;
                    }
                }
            }
            //滑出屏幕高度一半中止播放
            int playPosition = mAdapter.getPlayPosition();
            if (playPosition != -1) {
                if (isOutSide) {
                    stopPlay();
                }
            }
複製代碼
視頻列表頁

一樣也是RecyclerView實現,這裏滑動播放邏輯跟新聞列表頁有點不一樣(純屬我的理解,理解錯了各位大佬別打我)。進入頁面播放第一個視頻,上滑會加載更多(demo裏面沒有實現)。上下滑動中止後,會播放當前屏幕徹底可見的第一個item的視頻。而且,當播放視頻時,點擊其餘item的任意位置,該item會滑動到頂部並播放視頻。當前視頻播放完畢後,若是列表頁後面還有視頻,會自動播放下一個,並將該item滑到頁面頂部。當退出視頻列表頁時,若是播放的不是第一個視頻,則不須要過渡動畫。 滑動監聽:post

if (newState == SCROLL_STATE_IDLE) {
                    LinearLayoutManager manager = (LinearLayoutManager) recyclerView.getLayoutManager();
                    int first = manager.findFirstVisibleItemPosition();
                    int pos = manager.findFirstCompletelyVisibleItemPosition();
                    if (pos != mAdapter.getPlayPosition()) {
                        View view = mRecycler.getChildAt(pos - first);
                        ImageView imageView = view.findViewById(R.id.adapter_video_list_image);
                        imageView.performClick();
                    }
                }
複製代碼

由於已經對滑動進行了監聽,因此自動播放下一個視頻能夠經過滑動item來實現:監聽視頻的播放事件,當視頻播放完畢後,判斷該視頻是不是最後一個,不是則滑到屏幕頂部,播放視頻。 PS:滑動要調用smoothScroll方法,不能直接調scroll。動畫

評論頁

評論頁只是一個播放器容器和一個顯示評論數據的recyclerView(demo裏面沒有作評論蓋樓),這裏不細說,詳見demoui

視頻平滑過渡切換

敲黑板
重點來了,第一眼看到視頻平滑過渡切換頁面,想到的就是google在5.0版本提供activity切換的共享元素動畫,但實操以後發現效果不怎麼理想。
效果如圖:
退出activity會閃屏
也試過,去掉系統的默認動畫,將主題設置爲透明,本身手動平移,放縮view,仍是有點問題(多是我姿式不對)。仍是會有上面的閃屏問題。
攤手.jpg

沒辦法羅,只能在當前activity裏面進行過渡了。這裏個人作法是在根佈局添加一個fragment。這裏着重說一下要注意的幾個地方吧:this

  • 須要重寫onBackPressed(),區分是否橫屏模式,是否顯示了評論頁,列表視頻頁,仍是普通新聞頁。
  • 列表視頻頁,普通新聞頁都須要記錄下當前播放的item的position,退出頁面會用到。
  • 列表視頻,評論頁請求回來的網絡數據不能過早顯示。
  • 過渡動畫須要在view繪製好後纔開始執行。

下面是頁面過渡的過程:

有點醜,將就點吧

  • 獲取view的屬性(寬高、位置),新聞的信息,並傳給fragment
  • fragment背景設置爲透明,改變關聯的view屬性,並開始動畫,還原背景色和view的屬性,這裏有個地方須要特別留意,若是你的播放容器跟我同樣是放在recyclerView裏面的,那麼位移的view必須是整個item!整個item!整個item!(子view總不可能跑出父view的範圍吧...)
  • 動畫完畢後顯示加載的網絡數據(按我的需求進行修改)
  • 退出fragment的時候,將動畫反轉一遍就OK啦。要注意當前播放的視頻是不是進來播放的那個,是的話才須要執行動畫哦。
FragmentTransaction transaction = getFragmentManager().beginTransaction();
        Bundle bundle = new Bundle();
        bundle.putParcelable("attr", attr);
        bundle.putParcelable("news", bean);
        commentFragment.setArguments(bundle);
        commentFragment.setOnCloseClickListener(this);
        transaction.add(R.id.fragment_video_list_comment_container, commentFragment);
        transaction.commit();
    }
複製代碼
mContainer.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            @Override
            public boolean onPreDraw() {
                //繪製完畢,開始執行動畫
                mContainer.getViewTreeObserver().removeOnPreDrawListener(this);
                mContainer.getLocationOnScreen(location);
                mContainer.setTranslationX(mAttr.getX() - location[0]);
                mContainer.setTranslationY(mAttr.getY() - location[1]);
                mContainer.setScaleX(mAttr.getWidth() / (float) mContainer.getMeasuredWidth());
                mContainer.setScaleY(mAttr.getHeight() / (float) mContainer.getMeasuredHeight());
                mRecycler.setAlpha(0);
                mTextView.setAlpha(0);
                mClose.setAlpha(0);
                mCommentNum.setAlpha(0);
                mContainer.animate().translationX(0).translationY(0).scaleX(1).scaleY(1).setDuration(DURATION);
                mRecycler.animate().alpha(1).setDuration(DURATION);
                mTextView.animate().alpha(1).setDuration(DURATION);
                mClose.animate().alpha(1).setDuration(DURATION);
                mCommentNum.animate().alpha(1).setDuration(DURATION);
                AssistPlayer.get().play(mContainer, null);
                return true;
            }
        });
複製代碼

大功告成
有疑問(播放器相關的點 這裏)或者demo有bug的能夠留言,看到會回覆的。

附上源碼(Kotlin版可能會有一點語法問題...)

Java_Demo

Kotlin_Demo

如需更多詳細的效果,可看下一篇博客

相關文章
相關標籤/搜索