簡體   English   中英

對話框打開時如何處理屏幕方向變化?

[英]How do I handle screen orientation changes when a dialog is open?

我有一個 android 應用程序,它已經在處理方向更改,即清單中有一個android:configChanges="orientation" ,活動中有一個onConfigurationChange()處理程序,它切換到適當的布局並准備它。 我有布局的橫向/縱向版本。

我面臨的問題是該活動有一個對話框,當用戶旋轉設備方向時該對話框可能會打開。 我也有對話框的橫向/縱向版本。

我應該着手更改對話框的布局還是鎖定活動的旋轉直到用戶關閉對話框。

鎖定應用程序的后一種選擇對我很有吸引力,因為它無需在對話框中執行任何特殊操作。 我假設我可能會在打開對話框時禁用方向,例如

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);

然后當它解散時

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);

那會是明智的做法嗎? 如果屏幕方向在鎖定時確實發生了變化,那么在解鎖時它會立即感知到方向變化嗎?

有其他選擇嗎?

我建議不要關閉屏幕旋轉,而不是這個處理對話框的配置更改。 您可以使用以下兩種方法之一:

第一個是在onSaveInstanceState(outState)方法中使用flag變量,並恢復對話onCreate(bundle)方法:

在這個例子中,我的標志變量被稱為'isShowing Dialog',當第一次由android系統調用onCreate方法時,bundle參數將為null並且沒有任何反應。 但是,當通過配置更改(屏幕旋轉)重新創建活動時,該包將具有以前由inSaveInstanceState(...)方法保存的布爾值isShowing Dialog,因此如果變量為true,則會再次創建對話框,這里的技巧是在對話框顯示時將標志設置為true,而在不顯示時將其設置為false,這是一個簡單但很簡單的技巧。

Class MyClass extends Activity {
    Boolean isShowingDialog = false;
    AlertDialog myDialog;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        if(savedInstanceState!=null){
            isShowingDialog = savedInstanceState.getBoolean("IS_SHOWING_DIALOG", false);
            if(isShowingDialog){
                createDialog();
            }
        }

    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        outState.putBoolean("IS_SHOWING_DIALOG", isShowingDialog);
        super.onSaveInstanceState(outState);
    }

    @Override
    protected void onPause() {
        if(myDialog!=null && myDialog.isShowing()) {
            myDialog.dismiss();
        }
    }

    private void createDialog() {
        AlertDialog.Builder dialog_builder = new AlertDialog.Builder(this);
        dialog_builder.setTitle("Some Title"):
        ... more dialog settings ...

        myDialog = dialog_builder.create();
        myDialog.show();
        isShowingDialog = true;
    }

    private void hideDialog(){
        myDialog.dismiss();
        isShowingDialog = false;
    }
}

第二種方法是使用片段組件保持其狀態的能力,主要思想是在片段內創建對話框,在配置更改期間存在分離和重新附加片段的問題(因為您需要關閉並顯示對話框正確),但解決方案與第一種方法非常相似。 這種方法的優點是,如果你有一個帶有幾個配置的AlertDialog,當重新創建片段時,不需要再次創建和設置對話框,只需將它設為show()並且由此保持AlertDialog狀態。分段。

我希望這有幫助。

我建議您的Dialog應該覆蓋onSaveInstanceState()onRestoreInstanceState(Bundle)以將其狀態保存到Bundle中。

然后,在Activity中覆蓋這些方法,檢查是否顯示Dialog,如果是,則調用對話框的方法來保存和恢復它的狀態。

如果要從片段顯示此對話框,則需要覆蓋OnActivityCreated(Bundle)而不是OnRestoreInstanceState

有關源示例,請參閱隨Android提供的內置時鍾應用程序,其中SetAlarm活動以這種方式處理TimePickerDialog。

如果您自己處理方向更改,那么這是一種方法。

我不會聲稱這是一個優雅的解決方案,但它的工作原理:

您可以通過使用靜態變量activeInstance跟蹤對話框中是否具有活動實例,並覆蓋onStart()以設置activeInstance = this和onCancel()以設置activeInstance = null。

提供一個靜態方法updateConfigurationForAnyCurrentInstance(),用於測試activeInstance變量,如果非null,則調用方法activeInstance.reInitializeDialog(),這是一個方法,您將編寫包含setContentView()調用以及連接處理程序的代碼對於對話框控件(按鈕onClick處理程序等 - 這是通常出現在onCreate()中的代碼)。 之后,您可以將任何顯示的數據還原到這些控件(來自對話框對象中的成員變量)。 因此,例如,如果您有一個要查看的項目列表,並且用戶在方向更改之前查看該列表的第三項,您將在updateConfigurationForAnyCurrentInstance()結束時重新顯示相同的項目三從對話框資源重新加載控件並重新連接控制處理程序。

然后,您可以在super.onCreate()之后立即從onCreate()調用相同的reInitializeDialog()方法,並放置onCreate()特定的初始化代碼(例如, 設置用戶可以選擇的項目列表,如如上所述)。

這將導致加載對話框新方向的相應資源(縱向或橫向)(前提是您有兩個定義了相同名稱的資源,一個在布局文件夾中,另一個在layout-land文件夾中,如常) 。

這里有一些名為YourDialog的代碼:

ArrayList<String> listOfPossibleChoices = null;
int currentUserChoice = 0;

static private YourDialog activeInstance = null;

@Override
protected void onStart() {
  super.onStart();
  activeInstance = this;
}

@Override
public void cancel() {
  super.cancel();
  activeInstance = null;
}


static public void updateConfigurationForAnyCurrentInstance() {
    if(activeInstance != null) {
        activeInstance.reInitializeDialog();
        displayCurrentUserChoice();
    }
}

private void reInitializeDialog() {
  setContentView(R.layout.your_dialog);
  btnClose = (Button) findViewById(R.id.btnClose);
  btnClose.setOnClickListener(this);
  btnNextChoice = (Button) findViewById(R.id.btnNextChoice);
  btnNextChoice.setOnClickListener(this);
  btnPriorChoice = (Button) findViewById(R.id.btnPriorChoice);
  btnPriorChoice.setOnClickListener(this);
  tvCurrentChoice = (TextView) findViewById(R.id.tvCurrentChoice);
}

private void displayCurrentUserChoice() {
  tvCurrentChoice.setText(listOfPossibleChoices.get(currentUserChoice));
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    reInitializeDialog();
    listOfPossibleChoices = new ArrayList<String>();
    listOfPossibleChoices.add("One");
    listOfPossibleChoices.add("Two");
    listOfPossibleChoices.add("Three");
    currentUserChoice = 0;
    displayCurrentUserChoice();
}

@Override
public void onClick(View v) {
    int viewID = v.getId();

    if(viewID == R.id.btnNextChoice) {
      if(currentUserChoice < (listOfPossibleChoices.size() - 1))
        currentUserChoice++;
        displayCurrentUserChoice();
      }
    }
    else if(viewID == R.id.btnPriorChoice) {
      if(currentUserChoice > 0) {
        currentUserChoice--;
        displayCurrentUserChoice();
      }
    }
    Etc.

然后,在主活動的onConfigurationChanged()方法中,只要OS調用onConfigurationChanged(),您就會調用YourDialog.updateConfigurationForAnyCurrentInstance()。

標題似乎從未解決過(Google Necro Direct)。

這是解決方案,符合要求。

創建活動時,記錄屏幕方向值。 當在您的活動上調用 onConfiguration change 時,比較方向值。 如果值不匹配,則觸發所有方向更改偵聽器,然后記錄新的方向值。

這里有一些建設性的代碼可以放入您的活動(或任何可以處理配置更改事件的對象)

int orientation; // TODO: record orientation here in your on create using Activity.this.getRequestedOrientation() to initialize!

public int getOrientation(){return orientation;}
public interface OrientationChangeListener {
    void onOrientationChange();
}
Stack<OrientationChangeListener> orientationChangeListeners = new Stack<>();
public void addOrientationChangeListener(OrientationChangeListener ocl){ ... }
public void removeOrientationChangeListener(OrientationChangeListener ocl){ ... }

這就是基本環境。 這是你的主管:

public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    if (orientation != newConfig.orientation)
        for (OrientationChangeListener ocl:orientationChangeListeners) ocl.onOrientationChange();
    orientation = newConfig.orientation;
}

在您的代碼模型中,您可能需要隨事件發送新配置,或隨事件發送兩個方向值。 但是,在事件處理期間, Activity.this.getOrientation().= Activity.this.getRequestedOrientation() (因為我們處於兩個邏輯值之間變化的邏輯狀態)。

在查看我的帖子時,我確定可能存在一些同步問題,有多個事件,這不是此代碼的錯誤,而是“Android 平台”的錯誤,因為每個窗口都沒有事實上的方向感處理程序。 因此首先破壞了使用 java 的多態優勢。

請參閱上面 Viktor Valencia 的回答。 這將與您將 createDialog() 移動到 onResume 的輕微調整完美配合。

@Override
protected void onResume() {
    super.onResume();
    if(isShowingDialog){
        createDialog();
    }
}

按照建議,在 onCreate 獲取布爾值 isShowingDialog 值,但等待 onResume 顯示對話框。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM