螢幕旋轉的適配問題以及遇到的一些坑

weixin_34402408發表於2017-12-18

原文地址:http://www.jianshu.com/p/19393bb08e4f

在手機APP開發的時候,一般預設會適配豎屏,遊戲開發除外。但是在Android平板電腦開發中,螢幕旋轉的問題比較退出,可以這樣說,平板電腦的最初用意就是橫屏使用的,比較方便,使用者會經常旋轉我們的螢幕。

這裡主要針對平板開發中的一些問題做一些總結。

###1、防止螢幕旋轉之後,Activity的銷燬問題。

為了適配螢幕,Activity預設在螢幕旋轉之後會銷燬並且重建,但是這種情況會造成使用者輸入資料的丟失(需要開發者手動去儲存和恢復,會帶來一定的工作量),Activity畢竟是重量級的元件,它的銷燬和重建會使得效能的下降,因此我們需要防止Activity的銷燬和重建。

####做法

在清單檔案中為Activity新增一些配置,configChanges屬性新增orientation|screenSize:

<activity
        android:name=".ui.activity.MainActivity"
        android:configChanges="orientation|screenSize"
        android:launchMode="singleTask"
        android:windowSoftInputMode="stateAlwaysHidden">
複製程式碼

通過上述的配置可以防止Activity的銷燬和重建。

###2、View螢幕旋轉適配

除了製作橫屏和豎屏兩份佈局檔案的方法之外,如果我們的View是動態新增到Window的,螢幕旋轉之後,我們的介面以及View需要做一些變動以適應螢幕。

我們可以複寫Activity的onConfigurationChanged方法,並且在裡面修改一些東西。

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

    //一些適配操作
}
複製程式碼

這裡舉個例子,如說我們的ListView右邊有一個字母索引控制元件,這個控制元件是直接new出來並且是直接覆蓋在ListView上面的。當螢幕旋轉之後,這個字母索引控制元件的位置需要重新整理(重新佈局以及繪製)。因為這個控制元件是在我們的ListView的右側,並且豎直方向居中。這時候我們就需要動態獲取螢幕上的ListView的寬高,然後才能計算出字母控制元件應該佈局的位置。

####但是這裡我們會遇到一些坑

直接通過View的getWidth方法或者先measure然後通過getMeasuredWidth方法獲取到的寬都是錯誤的,獲取到的是螢幕旋轉之前的值,如下面的程式碼所示。但是我需要的是ListView實時的寬高值,這時候我們只能手動去計算。例如我們要獲取ListView的高度,那麼我們可以先拿到Window的總高度,然後減去狀態列、Toolbar的高度來獲取(這裡只是一個例子,具體做法需要具體分析)。

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

    //一些適配操作
    WindowManager wm = getWindowManager();//Activity可以直接獲取WindowManager
    //  WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
    final int windowWidth = wm.getDefaultDisplay().getWidth();
    final int windowHeight = wm.getDefaultDisplay().getHeight();

    //手動去計算ListView的寬高
    final int mListViewWidth = windowWidth;
    final int mListViewHeight = windowHeight - statusbarHeight - toolbarHeight;

    //下面獲取ListView的寬高是有問題的
    //  mListView.measure(0, 0);
    //  mListView.getMeasuredWidth();
    //  mListView.getMeasuredHeight();

    //  mListView.getWidth();
    //  mListView.getHeight();

	//	。。。其他適配操作
}
複製程式碼

###螢幕旋轉的不確定性問題

最近又遇到螢幕旋轉相關的新的問題,因此記錄下來。我們知道,在Activity、View、Fragment等旋轉的時候,如果你在清單檔案中配置不重新建立的話,就會呼叫onConfigurationChanged方法。

但是問題來了,這個問題有一些不確定性因素,比如說當你的頁面或者View被遮擋住(Stop)的時候就不會回撥onConfigurationChanged這個方法。這比較略坑,會帶來一些UI的偶發性問題。

解決辦法就是我們自定義一個廣播接受者專門用來接受onConfigurationChanged這個廣播,這樣子就可以確保,無論什麼情況下,系統ConfigurationChanged的時候你的程式碼都會被執行。

自定義的ConfigurationChangeReceiver如下,這裡提供一個靜態方法方便註冊。

public abstract class ConfigurationChangeReceiver extends BroadcastReceiver {

    private static final String TAG = ConfigurationChangeReceiver.class.getSimpleName();

    public static IntentFilter getIntentFilter() {
	IntentFilter filter = new IntentFilter();
	filter.addAction("android.intent.action.CONFIGURATION_CHANGED");
	return filter;
    }
}
複製程式碼

接下類在Activity或者Fragment中的正確位置註冊(onAttachedToWindow、onDetachedFromWindow):

private void initConfigurationChangeReceiver() {
    mConfigurationChangeReceiver = new ConfigurationChangeReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            //你的螢幕適配程式碼
        }
    };
    this.registerReceiver(mConfigurationChangeReceiver, ConfigurationChangeReceiver.getIntentFilter());
}
複製程式碼

記得反註冊,防止記憶體洩漏哦。

private void unRegisterConfigurationChangeReceiver() {
    if (mConfigurationChangeReceiver != null) {
        this.unregisterReceiver(mConfigurationChangeReceiver);
    }
}
複製程式碼

如果覺得我的文字對你有所幫助的話,歡迎關注我的公眾號:

我的群歡迎大家進來探討各種技術與非技術的話題,有興趣的朋友們加我私人微信huannan88,我拉你進群交(♂)流(♀)

相關文章