2011-04-08 68 views
10

我有一個Android應用程序已經處理方向的變化,即清單中有android:configChanges="orientation"和活動中的onConfigurationChange()處理程序切換到適當的佈局並進行準備。我有一個風景/肖像版本的佈局。如何在對話框打開時處理屏幕方向更改?

我面對的問題是,活動有一個對話框,當用戶旋轉設備方向時可以打開對話框。我也有對話的風景/肖像版本。

我應該着手改變對話框的佈局或者鎖定活動的旋轉,直到用戶關閉對話框。

鎖定應用程序的後一個選項對我有吸引力,因爲它省去了在對話框中做任何特殊的操作。我假設一個對話框打開時,我可能會禁用的方位,如

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR); 

,然後當它駁回

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR); 

那會是一個明智的事是什麼?如果屏幕方向在鎖定時發生了變化,它會在解鎖時立即感應到方向變化嗎?

有替代品嗎?

+1

我認爲如果用戶在顯示對話框時無法旋轉屏幕,這將會是一種奇怪的用戶體驗。 – Flo 2011-04-08 10:01:22

+0

可能但他們很快就會學會不這樣做。在打開對話框的同時進行旋轉意味着保存對話框狀態,解除對話框,再次打開對話框,並將原來位於onCreateDialog中的所有邏輯放入onPrepareDialog中,最後恢復狀態。有點亂。 – locka 2011-04-08 11:10:37

+0

當然,他們可以學習它,但是當我使用應用程序時,我希望它適合Android的整體體驗。標準Android應用程序的整體體驗並不妨礙我隨時隨地旋轉我的設備。當然,更容易阻止旋轉,但用戶不關心它是否更容易實現,他們只對應用程序的行爲感興趣。只是我2美分。 – Flo 2011-04-08 11:29:05

回答

0

我建議你的對話框應該覆蓋onSaveInstanceState()onRestoreInstanceState(Bundle)把它的狀態保存到一個Bundle中。

然後重寫Activity中的這些方法,檢查是否顯示對話框,如果是 - 調用對話框的方法來保存和恢復它的狀態。

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

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

0

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

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

您可以跟蹤的對話是否有對話框類本身內部的活動實例,通過使用一個靜態變量activeInstance,和重寫onStart()來設置activeInstance = this和onCancel()來設置activeInstance = null。

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

你會再調用從的onCreate()相同reInitializeDialog()方法,之後super.onCreate(),並把你的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()方法,你只需調用YourDialog.updateConfigurationForAnyCurrentInstance()每當onConfigurationChanged()被稱爲操作系統。

2

我會建議不關閉屏幕旋轉,而不是這個句柄對話框的配置更改。你可以使用這兩種方法對於此的一個:

第一個是使用的onSaveInstanceState(outState)方法的標誌變量,並恢復對話的onCreate(捆綁)方法:

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

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狀態由分段。

我希望這會有所幫助。