天天看點

GsyVideoPlayer視訊分析(三)------------全屏實作

首先思考以下幾個問題:

1.點選全屏按鈕,視訊是怎麼填充整個螢幕的?(以及視訊放大時的動畫效果實作)

2.視訊填充螢幕後,又是如何實作橫屏的?

3.視訊是如何做到,清單中的視訊和放大後的視訊,無縫銜接的?

依舊通過代碼分析:

//設定全屏按鍵功能
gsyVideoPlayer.getFullscreenButton().setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        resolveFullBtn();
    }
});      

全屏按鈕由一個點選事件觸發

public void resolveFullBtn() {
    if (fullViewContainer == null) {
        return;
    }
    if (!isFull) {
        resolveToFull();
    } else {
        resolveMaterialToNormal(gsyVideoPlayer);
    }
}      

fullViewContain是在ListVideoUtil初始化的時候設定的,具體分析可以檢視 http://blog.csdn.net/qq_15631341/article/details/74332254

代碼的意思是:

如果目前不是全屏,走resolveToFull;

如果目前是全屏,走resolveMaterialToNormal;

我們先分析展示全屏的過程,

/**
 * 處理全屏邏輯
 */
private void resolveToFull() {
    systemUiVisibility = ((Activity) context).getWindow().getDecorView().getSystemUiVisibility();
    CommonUtil.hideSupportActionBar(context, hideActionBar, hideStatusBar);//根據需求隐藏actionbar和statusbar
    if (hideKey) {
        hideNavKey(context);
    }
    isFull = true;
    //将gsyVideoplayer從原來的容器中剝離,即gsyVideoPlayer不在顯示在ListView的摸一個item上了
   ViewGroup viewGroup = (ViewGroup) gsyVideoPlayer.getParent();
       
//此處需要注意,gsyvideo還沒有從listview的item上移除時,儲存了目前的布局資訊,用于後面動畫的展示      
  listParams = gsyVideoPlayer.getLayoutParams(); if (viewGroup != null) { listParent = viewGroup; viewGroup.removeView(gsyVideoPlayer); }  gsyVideoPlayer.setIfCurrentIsFullscreen(true); gsyVideoPlayer.getFullscreenButton().setImageResource(gsyVideoPlayer.getShrinkImageRes());//替換全屏按鈕的圖檔為退出全屏的圖檔 gsyVideoPlayer.getBackButton().setVisibility(View.VISIBLE); //初始化旋轉工具 orientationUtils = new OrientationUtils((Activity) context, gsyVideoPlayer); orientationUtils.setEnable(isAutoRotation()); gsyVideoPlayer.getBackButton().setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { resolveMaterialToNormal(gsyVideoPlayer);//設定退出全屏監聽 } }); if (showFullAnimation) { if (fullViewContainer instanceof FrameLayout) { //目前隻做了frameLoayout的判斷 resolveMaterialAnimation(); } else { resolveFullAdd(); } } else { resolveFullAdd(); }}

如果設定的需要顯示動畫且目前的容器是FrameLayout就執行resolveMaterialAnimation();

否則執行resolveFullAdd()方法;即這兩種方法的差別是一個是有動畫效果的,一個是無動畫效果的;

先來看一下沒有動畫效果的是如何實作的?

/**
 * 添加到全屏父布局裡
 */
private void resolveFullAdd() {
    fullViewContainer.setBackgroundColor(Color.BLACK);
    fullViewContainer.addView(gsyVideoPlayer);
    resolveChangeFirstLogic(50);
}      

就是把一開始設定的fullViewContain的背景改為黑色,再把gsyVideoPlayer的布局添加進來,最後執行resolveChangeFirstLogic(50)方法;

再來看一下有動畫效果的是 如何實作的?

/**
 * 如果是5.0的動畫開始位置
 */
private void resolveMaterialAnimation() {
    listItemRect = new int[2];
    listItemSize = new int[2];
    saveLocationStatus(context, hideStatusBar, hideActionBar);//儲存gsyvideoplayer在listview的item中的位置和大小
    FrameLayout.LayoutParams lpParent = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
    FrameLayout frameLayout = new FrameLayout(context);
    frameLayout.setBackgroundColor(Color.BLACK);
    FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(listItemSize[0], listItemSize[1]);
    lp.setMargins(listItemRect[0], listItemRect[1], 0, 0);
    frameLayout.addView(gsyVideoPlayer, lp);
    fullViewContainer.addView(frameLayout, lpParent);
    handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            //開始動畫
            TransitionManager.beginDelayedTransition(fullViewContainer);
            resolveMaterialFullVideoShow(gsyVideoPlayer);
            resolveChangeFirstLogic(600);
        }
    }, 300);
}      
/**
 * 儲存大小和狀态
 */
private void saveLocationStatus(Context context, boolean statusBar, boolean actionBar) {
    listParent.getLocationOnScreen(listItemRect);//擷取listView中的gsyvideoplayer相對于螢幕的左邊距和上邊距并存入listItemRect中
    int statusBarH = getStatusBarHeight(context);
    int actionBerH = getActionBarHeight((Activity) context);
    if (statusBar) {
        listItemRect[1] = listItemRect[1] - statusBarH;
    }
    if (actionBar) {
        listItemRect[1] = listItemRect[1] - actionBerH;
    }
    listItemSize[0] = listParent.getWidth();
    listItemSize[1] = listParent.getHeight();
}      

listParent是在resolveToFull中儲存的gsyvideoplayer在listView的item中的布局參數;

GsyVideoPlayer視訊分析(三)------------全屏實作

上面的全屏動畫在handler的post方法之前,先構造了左邊這個布局,listItemRect标注反了,需要互換一下,不好意思,不會畫圖,将就一下,并把它加入到fullViewContain中;隻不過因為demo中的左右邊距都為0,是以listItemRect[0]就是0,listItemRect[1]就是上邊距再加上statusbar和actionbar的高度

/**
 * 如果是5.0的,要從原位置過度到全屏位置
 */
private void resolveMaterialFullVideoShow(GSYBaseVideoPlayer gsyVideoPlayer) {
    FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) gsyVideoPlayer.getLayoutParams();
    lp.setMargins(0, 0, 0, 0);
    lp.height = ViewGroup.LayoutParams.MATCH_PARENT;
    lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
    lp.gravity = Gravity.CENTER;
    gsyVideoPlayer.setLayoutParams(lp);
    gsyVideoPlayer.setIfCurrentIsFullscreen(true);
}      

在resolveMaterialFullVideoShow方法執行後,變為右邊那張圖;

至于中間的動畫效果:隻要

TransitionManager.beginDelayedTransition(fullViewContainer);

科普1:

要改變某個控件的位置,可以用修改布局參數後setLayoutParams,如果想給這個過程加上動畫效果,則可以在父節點上調用TransitionManager.beginDelayedTransition

無論是resolveToFull還是resolveMaterialToNormal至此已經完成了全屏變化;兩個方法最後都調用了resolveChangeFirstLogic

/**
 * 是否全屏一開始馬上自動橫屏
 */
private void resolveChangeFirstLogic(int time) {
    if (isFullLandFrist()) {
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                if (orientationUtils.getIsLand() != 1) {
                    orientationUtils.resolveByClick();
                }
            }
        }, time);
    }
    gsyVideoPlayer.setIfCurrentIsFullscreen(true);
    if (videoAllCallBack != null) {
        Debuger.printfLog("onEnterFullscreen");
        videoAllCallBack.onEnterFullscreen(this.url);
    }
}      

該方法是用來實作全屏後的螢幕旋轉;

/**
 * 點選切換的邏輯,比如豎屏的時候點選了就是切換到橫屏不會受螢幕的影響
 */
public void resolveByClick() {
    mClick = true;
    if (mIsLand == 0) {
        screenType = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
        activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        gsyVideoPlayer.getFullscreenButton().setImageResource(gsyVideoPlayer.getShrinkImageRes());
        mIsLand = 1;
        mClickLand = false;
    } else {
        screenType = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
        activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        if (gsyVideoPlayer.isIfCurrentIsFullscreen()) {
            gsyVideoPlayer.getFullscreenButton().setImageResource(gsyVideoPlayer.getShrinkImageRes());
        } else {
            gsyVideoPlayer.getFullscreenButton().setImageResource(gsyVideoPlayer.getEnlargeImageRes());
        }
        mIsLand = 0;
        mClickPort = false;
    }

}      

這一塊代碼病史很難,就是橫屏設定Activity為豎屏,豎屏就設定Activity為橫屏;

最後解釋一下,從清單視訊到全屏視訊的過程中,無縫銜接了,原因就是,隻是GsyVideoPlayer這個布局換了一個父控件,GsyVideoManager中的medieplayer并沒有停止播放,是以視訊無縫銜接了。

最後留一個問題,大家自己思考吧,如何從全屏再回到清單視訊????

從resolveMaterialToNormal(gsyVideoPlayer)分析開始。