【Android】android開發---實現屏幕旋轉的兩種方法

前言

爲實現播放器全屏豎屏切換,還可鎖住橫屏,解鎖後又可以跟隨傳感器變化。


正文

方法一:通過控制android:screenOrientation屬性控制橫豎屏

1.使用 SCREEN_ORIENTATION_SENSOR 參數設置其可以跟隨傳感器

this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);

2.當全屏時點擊鎖住,使用  SCREEN_ORIENTATION_LOCKED 鎖住屏幕

this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);

3.點擊解鎖,再設置爲跟隨傳感器

this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);

 這時候就有一個新的問題給大家,如果要實現點擊播放器放大按鈕,變成全屏,全屏後還可以跟隨傳感器變化,大家會怎麼做?

你可能會想使用 SCREEN_ORIENTATION_LANDSCAPE 使其橫屏,接着設置爲跟隨傳感器 ,也就是以下兩行代碼。

this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);

可是結果總是這麼不盡如人意。點擊"開啓旋轉"會發現旋轉成橫屏後會自動又旋迴豎屏(因爲傳感器是讀取你現在的手機狀態),顯而易見,這種體驗很不好。

所以我們就有了方法二

方法二:通過監聽屏幕旋轉角度控制橫豎屏

前期配置:

AndroidManifest.xml

android:configChanges="orientation|screenSize">

使其不會重新調用onCreate方法,而是調用onConfigurationChanged,避免出現奇怪的問題。

基礎類:

別看代碼多,直接拷去用就好

package com.aliyun.vodplayerview.utils;

import android.content.Context;
import android.hardware.SensorManager;
import android.view.OrientationEventListener;


/*
 * Copyright (C) 2010-2018 Alibaba Group Holding Limited.
 */

/**
 * 屏幕方向監聽類
 */
public class OrientationWatchDog {
    private static final String TAG = OrientationWatchDog.class.getSimpleName();

    private Context mContext;
    //系統的屏幕方向改變監聽
    private OrientationEventListener mLandOrientationListener;
    //對外的設置的監聽
    private OnOrientationListener mOrientationListener;
    //上次屏幕的方向
    private Orientation mLastOrientation = Orientation.Port;

    /**
     * 屏幕方向
     */
    private enum Orientation {
        /**
         * 豎屏
         */
        Port,
        /**
         * 橫屏
         */
        Land
    }


    public OrientationWatchDog(Context context) {
        mContext = context.getApplicationContext();
    }

    /**
     * 開始監聽
     */
    public void startWatch() {
        VcPlayerLog.e(TAG, "startWatch");
        if (mLandOrientationListener == null) {
            mLandOrientationListener = new OrientationEventListener(mContext,
                    SensorManager.SENSOR_DELAY_NORMAL) {
                @Override
                public void onOrientationChanged(int orientation) {
                    //這裏的|| 和&& 不能弄錯!!
                    //根據手機的方向角度計算。在90和180度上下10度的時候認爲橫屏了。
                    //豎屏類似。
                    boolean isLand = (orientation < 100 && orientation > 80)
                            || (orientation < 280 && orientation > 260);

                    boolean isPort = (orientation < 10 || orientation > 350)
                            || (orientation < 190 && orientation > 170);

                    if (isLand) {
                        if (mOrientationListener != null) {
                            mOrientationListener.changedToLandScape(mLastOrientation == Orientation.Port);
                        }
                        mLastOrientation = Orientation.Land;
                    } else if (isPort) {
                        if (mOrientationListener != null) {
                            mOrientationListener.changedToPortrait(mLastOrientation == Orientation.Land);
                        }
                        mLastOrientation = Orientation.Port;
                    }

                }
            };
        }

        mLandOrientationListener.enable();
    }

    /**
     * 結束監聽
     */
    public void stopWatch() {
        if (mLandOrientationListener != null) {
            mLandOrientationListener.disable();
        }
    }

    /**
     * 銷燬監聽
     */
    public void destroy() {
        stopWatch();
        mLandOrientationListener = null;
    }

    /**
     * 屏幕方向變化事件
     */
    public interface OnOrientationListener {
        /**
         * 變爲Land
         *
         * @param fromPort 是否是從豎屏變過來的
         */
        void changedToLandScape(boolean fromPort);

        /**
         * 變爲Port
         *
         * @param fromLand 是否是從橫屏變過來的
         */
        void changedToPortrait(boolean fromLand);
    }

    /**
     * 設置屏幕方向變化事件
     *
     * @param l 事件監聽
     */
    public void setOnOrientationListener(OnOrientationListener l) {
        mOrientationListener = l;
    }

}

使用方法:

1.實現OnOrientationListener接口,將旋轉時需要實現的操作放進去

  界面:

  MainAcitivity:

package com.eddie.screenorientationdemo;

import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;

import com.eddie.screenorientation.OrientationWatchDog;



public class MainActivity extends AppCompatActivity implements OrientationWatchDog.OnOrientationListener {

    TextView mTvStartSpan;
    TextView mTvStopSpan;
    /**
     * 監聽類
     */
    private OrientationWatchDog mOrientationWatchDog;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTvStartSpan = findViewById(R.id.tv_start_span);
        mTvStopSpan = findViewById(R.id.tv_stop_span);
        initOrientationWatchdog();
        mTvStartSpan.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mOrientationWatchDog != null) {
                    mOrientationWatchDog.startWatch();
                }
            }
        });
        mTvStopSpan.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mOrientationWatchDog != null) {
                    mOrientationWatchDog.stopWatch();
                }
            }
        });
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
    }

    @Override
    public void changedToLandScape(boolean fromPort) {
        //如果不是從豎屏變過來,也就是一直是橫屏的時候,就不用操作了
        if (!fromPort) {
            return;
        }
        this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
    }

    @Override
    public void changedToPortrait(boolean fromLand) {
        //如果沒有轉到過橫屏,就不讓他轉了。防止豎屏的時候點橫屏之後,又立即轉回來的現象
        if (!fromLand) {
            return;
        }
        this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
    }

    /**
     * 初始化屏幕方向監聽器。用來監聽屏幕方向。結果通過OrientationListener回調出去。
     */
    private void initOrientationWatchdog() {
        mOrientationWatchDog = new OrientationWatchDog(this);
        mOrientationWatchDog.setOnOrientationListener(this);
    }
}

2.初始化監聽器

 /**
     * 初始化屏幕方向旋轉。用來監聽屏幕方向。結果通過OrientationListener回調出去。
     */
    private void initOrientationWatchdog() {
        final Context context = getContext();
        mOrientationWatchDog = new OrientationWatchDog(context);
        mOrientationWatchDog.setOnOrientationListener(new InnerOrientationListener(this));
    }

3.在你需要跟隨傳感器變化的地方,開啓監聽器

if (mOrientationWatchDog != null) {
    mOrientationWatchDog.startWatch();
}

 4.別忘了在不使用的時候關閉監聽器

if (mOrientationWatchDog != null) {
    mOrientationWatchDog.stopWatch();
}

源碼: github

借鑑阿里雲播放器源碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章