前言
爲實現播放器全屏豎屏切換,還可鎖住橫屏,解鎖後又可以跟隨傳感器變化。
正文
方法一:通過控制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
借鑑阿里雲播放器源碼