2011-04-08 65 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状态由分段。

我希望这会有所帮助。