打开对话框时如何处理屏幕方向更改?

时间:2011-04-08 09:04:36

标签: java android

我有一个Android应用程序已经处理了方向的更改,即清单中有一个android:configChanges="orientation",活动中有一个onConfigurationChange()处理程序切换到相应的布局并准备它。我有一个横向/纵向版本的布局。

我面临的问题是活动有一个对话框,当用户旋转设备方向时,该对话框可以打开。我还有对话框的横向/纵向版本。

我是否应该动态更改对话框的布局,或者锁定活动的旋转,直到用户解除对话框为止。

锁定应用程序的后一个选项会吸引我,因为它可以节省在对话框中执行任何特殊操作的操作。我假设我可能会在对话框打开时禁用方向,例如

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);

然后当它解散时

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);

这是明智的做法吗?如果屏幕方向在锁定时确实发生了变化,它会在解锁后立即感知方向变化吗?

有替代方案吗?

4 个答案:

答案 0 :(得分:2)

我建议不要关闭屏幕旋转,而不是此处理对话框的配置更改。您可以使用以下两种方法之一:

第一个是在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状态。片段。

我希望这会有所帮助。

答案 1 :(得分:0)

我建议您的对话框覆盖onSaveInstanceState()onRestoreInstanceState(Bundle)以将其状态保存到捆绑包中。

然后在Activity中覆盖这些方法,检查是否显示了Dialog,如果是,则调用对话框的方法来保存和恢复它的状态。

如果您要从片段中显示此对话框,则需要覆盖OnActivityCreated(Bundle)而不是OnRestoreInstanceState

有关源示例,请参阅随Android提供的内置时钟应用,其中SetAlarm Activity以这种方式处理TimePickerDialog。

答案 2 :(得分:0)

如果您自己处理方向更改,那么这是一种方法。

我不会声称这是一个优雅的解决方案,但它确实有效:

您可以通过使用静态变量activeInstance跟踪对话框中是否有活动实例,并覆盖onStart()以设置activeInstance = this和onCancel()以设置activeInstance = null。

提供一个静态方法updateConfigurationForAnyCurrentInstance(),用于测试activeInstance变量,如果为非null,则调用方法activeInstance.reInitializeDialog(),这是一个方法,您将编写该方法以包含setContentView()调用以及代码连接对话框控件的处理程序(按钮onClick处理程序等 - 这是通常出现在onCreate()中的代码)。之后,您可以将任何显示的数据还原到这些控件(来自对话框对象中的成员变量)。因此,例如,如果您有一个要查看的项目列表,并且用户在方向更改之前查看该列表的第三项,您将在updateConfigurationForAnyCurrentInstance()结束时重新显示相同的项目三从对话框资源重新加载控件并重新连接控制处理程序。

然后在super.onCreate()之后立即从onCreate()调用相同的reInitializeDialog()方法,并放置onCreate()特定的初始化代码(例如,设置列表在该呼叫之后用户可以选择的项目,如上所述。

这将导致加载对话框新方向的相应资源(纵向或横向)(前提是您定义了两个具有相同名称的资源,一个位于布局文件夹中,另一个位于布局中-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()方法中,只要操作系统调用onConfigurationChanged(),您就会调用YourDialog.updateConfigurationForAnyCurrentInstance()。

答案 3 :(得分:0)

标题似乎从未解析过(Google Necro Direct)。

这是解决方案,符合要求。

创建活动后,记录屏幕方向值。 在活动上调用onConfiguration更改时,请比较方向值。如果这些值不匹配,则触发所有方向更改侦听器,然后记录新的方向值。

这里有一些建设性的代码可以放入您的活动(或任何可以处理配置更改事件的对象)

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的多态性优势。