【问题标题】:ActionBar in a DialogFragmentDialogFragment 中的 ActionBar
【发布时间】:2012-07-11 03:14:22
【问题描述】:

在我的 Galaxy Tab 10.1 上的日历应用程序中,当创建一个新事件时,会在标题栏/操作栏区域出现一个对话框,其中包含完成和取消按钮。

我想在我的应用中实现这一点。除了在我的DialogFragment 子类中覆盖onCreateOptionsMenu 之外,我还尝试使用setHasOptionsMenu(true),但我的操作项没有出现。我也尝试从onCreateView 中调用getDialog().getActionBar(),但它总是返回null

如果我启动 Activity 而不是显示一个对话框,但它会占据整个屏幕,我就能完成这项工作。有没有使用DialogFragment 的标准方法来做到这一点?

【问题讨论】:

  • 这可能是一个看起来像对话框而不是“真正的对话框”的活动。
  • "最新的功能被添加到支持库的工具栏版本中,并且它们可以在任何可以使用支持库的设备上使用。因此,您应该使用支持库的工具栏类来实现你的活动的应用栏。” developer.android.com/training/appbar/setting-up

标签: android android-actionbar android-dialogfragment


【解决方案1】:

使用来自google group post 的想法,我能够将其从活动样式中拉出来。您最好将高度和宽度修改为您选择的“动态”大小。然后设置你想要的任何 ActionBar 按钮

<style name="PopupTheme" parent="android:Theme.Holo.Light.Dialog">
    <item name="android:windowIsFloating">false</item>
    <item name="android:windowContentOverlay">@null</item>
    <item name="android:windowSoftInputMode">stateAlwaysHidden</item>
    <item name="android:windowActionModeOverlay">true</item>
    <item name="android:windowIsTranslucent">true</item>
</style>

--

public static void showAsPopup(Activity activity) {
    //To show activity as dialog and dim the background, you need to declare android:theme="@style/PopupTheme" on for the chosen activity on the manifest
    activity.requestWindowFeature(Window.FEATURE_ACTION_BAR);
    activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND,
            WindowManager.LayoutParams.FLAG_DIM_BEHIND);
    LayoutParams params = activity.getWindow().getAttributes(); 
    params.height = 850; //fixed height
    params.width = 850; //fixed width
    params.alpha = 1.0f;
    params.dimAmount = 0.5f;
    activity.getWindow().setAttributes((android.view.WindowManager.LayoutParams) params); 
    setContentView(R.layout.activity_main);
}

【讨论】:

  • 你刚刚丰富了我的应用程序!
  • 对话框的actionbar好像没有自定义样式。它获取默认样式。知道如何使操作栏具有自定义样式吗?
  • @kilaka 对(真的)迟到的回复感到抱歉。此代码 - 不会 - 为您提供问题示例图像中的样式/主题。您必须创建一个类似于 jgilfelt.github.io/android-actionbarstylegenerator 的主题,然后如果您仍然获得默认的全息主题,您可能必须在每个 res/values-XX/syles.xml 中声明主题。
  • 我使用了一个自定义对话框,它不想显示我的操作栏图标,除非我使用了 android.R.style.Theme_*_DialogWhenLarge 样式(这使得对话框在我的手机上全屏显示)。在自定义样式中使用 false 并设置 myDialog.requestWindowFeature(Window.FEATURE_ACTION_BAR);解决了,不需要别的了。感谢这篇文章!
  • 我想达到同样的效果,但我很困惑:我必须在哪里放置 showAdPopup Methode?什么是活动参数?这是应该显示为弹出窗口的活动还是应该显示片段作为弹出窗口的活动?
【解决方案2】:

如果您使用的是 ActionBarSherlock,请将主题声明如下:

<style name="PopupTheme" parent="Theme.Sherlock">
    <item name="android:windowFrame">@null</item>
    <item name="android:windowIsFloating">false</item>
    <item name="android:windowContentOverlay">@null</item>
    <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
    <item name="android:windowSoftInputMode">stateAlwaysHidden</item>
    <item name="android:windowActionModeOverlay">true</item>
    <item name="android:colorBackgroundCacheHint">@null</item>
    <item name="android:windowCloseOnTouchOutside">true</item>
    <item name="android:windowIsTranslucent">true</item>
    <item name="windowContentOverlay">@null</item>
</style>

并且,根据Luke Sleeman's answer,使用 PopupTheme 初始化一个 SherlockActivity

private void showAsPopup(SherlockActivity activity) {
    //To show activity as dialog and dim the background, you need to declare android:theme="@style/PopupTheme" on for the chosen activity on the manifest
    //activity.requestWindowFeature(Window.FEATURE_ACTION_BAR); // NO NEED to call this line.
    activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND,
            WindowManager.LayoutParams.FLAG_DIM_BEHIND);
    LayoutParams params = activity.getWindow().getAttributes(); 
    params.alpha = 1.0f;
    params.dimAmount = 0.5f;
    activity.getWindow().setAttributes((android.view.WindowManager.LayoutParams) params); 

    // This sets the window size, while working around the IllegalStateException thrown by ActionBarView
    activity.getWindow().setLayout(width,height);
}

结果:

【讨论】:

    【解决方案3】:

    在实施 StrikeForceZero 和 Luke Sleeman 建议的解决方案时遇到了一些麻烦,所以我想贡献我的经验。我确定我缺少一些东西,因此非常感谢您的反馈。

    我做了以下事情:

    1. 使用提供的 PopupTheme 创建样式,直接复制/粘贴:

      <style name="PopupTheme" parent="android:Theme.Holo.Light.Dialog">
          <item name="android:windowIsFloating">false</item>
          <item name="android:windowContentOverlay">@null</item>
          <item name="android:windowSoftInputMode">stateAlwaysHidden</item>
          <item name="android:windowActionModeOverlay">true</item>
          <item name="android:windowIsTranslucent">true</item>
      </style>
      
    2. 将 showAsPopup() 方法添加为片段中的方法,该方法将打开假对话片段,直接复制/粘贴:

      private void showAsPopup(Activity activity) {
          //To show activity as dialog and dim the background, you need to declare android:theme="@style/PopupTheme" on for the chosen activity on the manifest
          activity.requestWindowFeature(Window.FEATURE_ACTION_BAR);
          activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND,
              WindowManager.LayoutParams.FLAG_DIM_BEHIND);
          LayoutParams params = activity.getWindow().getAttributes(); 
          params.alpha = 1.0f;
          params.dimAmount = 0f;
          activity.getWindow().setAttributes((android.view.WindowManager.LayoutParams) params); 
      
          // This sets the window size, while working around the IllegalStateException thrown by ActionBarView
          activity.getWindow().setLayout(850,850);
      }
      
    3. 使用简单的 new() 调用创建新活动的实例,然后将其传递给 showAsPopup() 方法:

      DialogTestActivity test = new DialogTestActivity();
      showAsPopup(test);
      
    4. 为了测试的目的(我只是想确认我可以打开一个显示为带有操作栏的对话框的活动)我使用了一个非常简单的测试,直接从按钮视图 api 演示中窃取(对于布局文件,参见 api 演示中的 buttons_1.xml):

      public class DialogTestActivity extends Activity {
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.buttons_test);
          }
      }
      

    不幸的是,每次我尝试此操作时,都会在第一次调用 activity.requestWindowFeature(Window.FEATURE_ACTION_BAR); 时得到一个未指定的空指针异常;

    04-29 16:39:05.361: W/System.err(15134): java.lang.NullPointerException
    04-29 16:39:05.361: W/System.err(15134):    at android.app.Activity.requestWindowFeature(Activity.java:3244)
    04-29 16:39:05.371: W/System.err(15134):    at packagenameremovedforlegalreasons.classname.showAsPopup(classname.java:602)
    04-29 16:39:05.371: W/System.err(15134):    at packagenameremovedforlegalreasons.classname.onMapLongClick(classname.java:595)
    04-29 16:39:05.371: W/System.err(15134):    at com.google.android.gms.maps.GoogleMap$5.onMapLongClick(Unknown Source)
    04-29 16:39:05.371: W/System.err(15134):    at com.google.android.gms.internal.k$a.onTransact(Unknown Source)
    04-29 16:39:05.381: W/System.err(15134):    at android.os.Binder.transact(Binder.java:310)
    04-29 16:39:05.381: W/System.err(15134):    at com.google.android.gms.maps.internal.IOnMapLongClickListener$Stub$Proxy.onMapLongClick(IOnMapLongClickListener.java:93)
    04-29 16:39:05.381: W/System.err(15134):    at maps.i.s.a(Unknown Source)
    04-29 16:39:05.381: W/System.err(15134):    at maps.y.v.d(Unknown Source)
    04-29 16:39:05.381: W/System.err(15134):    at maps.y.bf.onLongPress(Unknown Source)
    04-29 16:39:05.381: W/System.err(15134):    at maps.d.v.onLongPress(Unknown Source)
    04-29 16:39:05.381: W/System.err(15134):    at maps.d.h.c(Unknown Source)
    04-29 16:39:05.381: W/System.err(15134):    at maps.d.h.c(Unknown Source)
    04-29 16:39:05.381: W/System.err(15134):    at maps.d.j.handleMessage(Unknown Source)
    04-29 16:39:05.391: W/System.err(15134):    at android.os.Handler.dispatchMessage(Handler.java:99)
    04-29 16:39:05.391: W/System.err(15134):    at android.os.Looper.loop(Looper.java:137)
    04-29 16:39:05.391: W/System.err(15134):    at android.app.ActivityThread.main(ActivityThread.java:5041)
    04-29 16:39:05.391: W/System.err(15134):    at java.lang.reflect.Method.invokeNative(Native Method)
    04-29 16:39:05.391: W/System.err(15134):    at java.lang.reflect.Method.invoke(Method.java:511)
    04-29 16:39:05.391: W/System.err(15134):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
    04-29 16:39:05.391: W/System.err(15134):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
    04-29 16:39:05.391: W/System.err(15134):    at dalvik.system.NativeStart.main(Native Method)
    

    从堆栈跟踪中可以看出,预期的行为是在 GoogleMap 实例上长按时打开窗口(使用 API 2 中的 MapFragments)。所以我的第一个想法是尝试从 Fragment 打开存在问题,所以我将调用传递回拥有的 Activity。同样的错误,同样没有附加信息。

    此时我最好的猜测是 new() 调用没有充分实例化类/视图,以便调用修改其视图。事实证明,这似乎至少在某种程度上是正确的,因为将视图修改代码迁移到活动中并以正常方式简单地打开活动:

    通话活动:

        public void openMapDialog()
        {
            Intent intent = new Intent(this, DialogTestActivity.class);
            startActivity(intent);
        }
    

    新课程代码:

        public class DialogTestActivity extends Activity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            // From: https://stackoverflow.com/questions/11425020/actionbar-in-a-dialogfragment
            this.requestWindowFeature(Window.FEATURE_ACTION_BAR);
            this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND, WindowManager.LayoutParams.FLAG_DIM_BEHIND);
            LayoutParams params = this.getWindow().getAttributes(); 
            params.alpha = 1.0f;
            params.dimAmount = 0f;
            this.getWindow().setAttributes((android.view.WindowManager.LayoutParams) params); 
    
            // This sets the window size, while working around the IllegalStateException thrown by ActionBarView
            this.getWindow().setLayout(600,600);
    
            setContentView(R.layout.buttons_test);
            }
        }
    

    所以我想我发布所有这些内容的目的是为了澄清,如果你想做上述海报所建议的事情,你不能只是 new() 一个活动并调用 showAsPopup()。这可能是我对 Android 显示的缺乏经验,但是虽然这似乎有点明显,但将 showAsPopup() 解释为由当前视图调用而不是正在创建的视图调用似乎也很自然,因为您正在传递活动实例(如果它应该像我最终做的那样在 onCreate() 中完成,那就是 this )。

    因此,如果意图是在 creating 活动而不是 created 活动中调用 showAsPopup(),那么如何获取之前可修改的 Activity 实例并不明显到 onCreate() 被调用。问题是你不能在调用 setContentView() 之后调用 requestWindowFeature() 之类的东西 (example),这是一个问题,因为它通常在 onCreate() 中调用。

    同样,如果有一种简单/更好的方法可以做到这一点,我将非常感谢您的反馈。希望这对想要使用这种方法的人有所帮助。

    【讨论】:

    • 谢谢,这对我有帮助。我解决问题的方法是将showAsPopup(Activity activity) 方法更改为“公共静态”方法,然后在其他任何事情之前从onCreate 调用它(super.onCreate 除外。
    • 感谢您解释原始答案失败的地方。请注意 Niak,您的方法不需要是静态的。
    • 很好的解释!有两件事仍然令人困惑:在第 2 点中,您正在撰写有关片段的文章。应该清楚的是,一个活动显示了另一个活动。不涉及任何片段。此外,必须在 App 清单中将 DialogTestActivity 的主题设置为 @style/PopupTheme。否则对话框/弹出窗口将无法正确显示。
    【解决方案4】:

    我花了很多时间来玩这个。接受的答案适用于galaxy nexus 7(Android 4.2),但在三星galaxy SIII(Android 4.1)和三星galaxy tab 10.2(Android 4.0)上失败,但有以下例外:

    IllegalStateException: ActionBarView can only be used with android:layout_width="match_parent" (or fill_parent)
    

    这是由ActionBarView.onMeasure(int, int) 中的代码引起的,该代码会检查以确保布局设置为 match_parent。正确的解决方案是通过 setLayout 而不是使用 setAttributes 来设置窗口的宽度。

    这是 showAsPopup() 的固定版本,适用于我测试过的所有设备:

    private void showAsPopup(Activity activity) {
        //To show activity as dialog and dim the background, you need to declare android:theme="@style/PopupTheme" on for the chosen activity on the manifest
        activity.requestWindowFeature(Window.FEATURE_ACTION_BAR);
        activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND,
                WindowManager.LayoutParams.FLAG_DIM_BEHIND);
        LayoutParams params = activity.getWindow().getAttributes(); 
        params.alpha = 1.0f;
        params.dimAmount = 0f;
        activity.getWindow().setAttributes((android.view.WindowManager.LayoutParams) params); 
    
        // This sets the window size, while working around the IllegalStateException thrown by ActionBarView
        activity.getWindow().setLayout(850,850);
    }
    

    为了完整起见,这里又是 PopupTheme:

    <style name="PopupTheme" parent="android:Theme.Holo.Light.Dialog">
        <item name="android:windowIsFloating">false</item>
        <item name="android:windowContentOverlay">@null</item>
        <item name="android:windowSoftInputMode">stateAlwaysHidden</item>
        <item name="android:windowActionModeOverlay">true</item>
        <item name="android:windowIsTranslucent">true</item>
    </style>
    

    【讨论】:

      【解决方案5】:

      就像 Veeti 暗示的那样,您可能想尝试使用对话框主题来实现 Activity。在 Android 清单中:

      <activity android:name=".YourActivity" android:theme="@android:style/Theme.Dialog </activity>
      

      希望这会有所帮助。

      【讨论】:

        【解决方案6】:

        我可能没有这方面的经验,但我会使用一个活动,添加操作栏项目,然后:

        &lt;activity android:name=".YourActivity" android:theme="@android:style/Theme.Holo.Light.Dialog" /&gt;

        希望有帮助!

        【讨论】:

        • 这确实成功地显示了看起来像对话框的活动,但仍然看不到操作栏。我还尝试使用继承自Theme.Holo.Light.Dialog 的自定义主题并将android:windowActionBar 属性设置为true。一旦我这样做了,我就会得到一个异常java.lang.IllegalStateException: ActionBarImpl can only be used with a compatible window decor layout
        【解决方案7】:

        我找到了一个很好的方法,在 DialogFragment 的 alertDialog 构建器上使用 setCustomTitle(也可以在 alertDialog 本身上使用)。

        public Dialog onCreateDialog(final Bundle savedInstanceState) {
            final AlertDialog.Builder builder = new AlertDialog.Builder(activity,...);
            final Toolbar toolbar = (Toolbar) inflater.inflate(R.layout.dialog_app_filter_toolbar, null, false);
            // <= prepare toolbar and dialog here
            return builder.create();
            }
        

        结果(来自my app):

        如果您不想使用 AlertDialog,您仍然可以在对话框布局中放置一个工具栏并使用它。

        【讨论】:

          【解决方案8】:

          我知道这不是真正的答案,但上面的解决方案似乎很不优雅,以至于人们可能认为完全避免操作栏会更容易,比如从带有 .noActionBar 的东西继承对话框主题,然后在顶部创建视图模仿动作栏的面板,至少这样它都保留在 xlm 中。

          【讨论】:

          • 如果不优雅,你的意思是太硬编码,给你:DisplayMetrics metrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(metrics); getWindow().setLayout(metrics.widthPixels - 80, metrics.heightPixels - 80);
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多