如何在对话框打开时处理屏幕方向更改?
我有一个Android应用程序已经处理方向的变化,即清单中有android:configChanges="orientation"
和活动中的onConfigurationChange()
处理程序切换到适当的布局并进行准备。我有一个风景/肖像版本的布局。如何在对话框打开时处理屏幕方向更改?
我面对的问题是,活动有一个对话框,当用户旋转设备方向时可以打开对话框。我也有对话的风景/肖像版本。
我应该着手改变对话框的布局或者锁定活动的旋转,直到用户关闭对话框。
锁定应用程序的后一个选项对我有吸引力,因为它省去了在对话框中做任何特殊的操作。我假设一个对话框打开时,我可能会禁用的方位,如
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
,然后当它驳回
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
那会是一个明智的事是什么?如果屏幕方向在锁定时发生了变化,它会在解锁时立即感应到方向变化吗?
有替代品吗?
我建议你的对话框应该覆盖onSaveInstanceState()
和onRestoreInstanceState(Bundle)
把它的状态保存到一个Bundle中。
然后重写Activity中的这些方法,检查是否显示对话框,如果是 - 调用对话框的方法来保存和恢复它的状态。
如果您从一个片段显示此对话框,则需要覆盖OnActivityCreated(Bundle)
而不是OnRestoreInstanceState
。
有关源示例,请参阅Android提供的内置时钟应用程序,其中SetAlarm Activity以这种方式处理TimePickerDialog。
如果您自己处理方向更改,那么这是一种方法。
我不会声称这是一个完美的解决方案,但它的工作原理:
您可以跟踪的对话是否有对话框类本身内部的活动实例,通过使用一个静态变量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()被称为操作系统。
我会建议不关闭屏幕旋转,而不是这个句柄对话框的配置更改。你可以使用这两种方法对于此的一个:
第一个是使用的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状态由分段。
我希望这会有所帮助。
我认为如果用户在显示对话框时无法旋转屏幕,这将会是一种奇怪的用户体验。 – Flo 2011-04-08 10:01:22
可能但他们很快就会学会不这样做。在打开对话框的同时进行旋转意味着保存对话框状态,解除对话框,再次打开对话框,并将原来位于onCreateDialog中的所有逻辑放入onPrepareDialog中,最后恢复状态。有点乱。 – locka 2011-04-08 11:10:37
当然,他们可以学习它,但是当我使用应用程序时,我希望它适合Android的整体体验。标准Android应用程序的整体体验并不妨碍我随时随地旋转我的设备。当然,更容易阻止旋转,但用户不关心它是否更容易实现,他们只对应用程序的行为感兴趣。只是我2美分。 – Flo 2011-04-08 11:29:05