在DialogFragment中的ActionBar

在我的Galaxy Tab 10.1上的日历应用程序中,创build新事件时,会在标题栏/动作栏区域中显示完成和取消button。

在这里输入图像说明

我想在我的应用程序中实现这一点。 我已经尝试使用setHasOptionsMenu(true)除了重写onCreateOptionsMenu在我的DialogFragment子类,但我的行动项目不会出现。 我也尝试从onCreateView调用getDialog().getActionBar() ,但它总是返回null

我能够得到这个工作,如果我开始一个Activity而不是显示一个对话框,但占用了整个屏幕。 有没有一个标准的方法来做到这一点使用DialogFragment

使用谷歌集团发布的想法,我能够把它从一个活动样式。 您可能希望将高度和宽度修改为您所select的“dynamic”尺寸。 然后设置你想要的任何ActionBarbutton

 <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); } 

如果您使用的是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的回答,用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); } 

结果:

在这里输入图像说明

在执行StrikeForceZero和Luke Sleeman的build议解决scheme时遇到了一些麻烦,所以我想提供我的经验。 我敢肯定,这只是我缺less的东西,所以反馈将不胜感激。

我所做的是以下几点:

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

     <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()调用创build新活动的实例,然后将其传递给showAsPopup()方法:

     DialogTestActivity test = new DialogTestActivity(); showAsPopup(test); 
  4. 对于testing的目的(我只是想确认,我可以打开一个活动,作为一个对话框与行动栏呈现)我使用了一个非常简单的testing,直接从button视图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)时,我得到一个未指定的空指针exception。

 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.isa(Unknown Source) 04-29 16:39:05.381: W/System.err(15134): at maps.yvd(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.dvonLongPress(Unknown Source) 04-29 16:39:05.381: W/System.err(15134): at maps.dhc(Unknown Source) 04-29 16:39:05.381: W/System.err(15134): at maps.dhc(Unknown Source) 04-29 16:39:05.381: W/System.err(15134): at maps.djhandleMessage(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)来打开窗口。 所以我的第一个想法是试图从片段中打开,所以我把这个callback传递给了自己的Activity。 同样的错误,同样没有额外的信息。

我最好的猜测是,new()调用没有充分实例化类/视图,以便调用修改其视图。 事实certificate,这似乎至less有些不错,因为将视图修改代码迁移到活动中,并以普通方式简单地打开活动工作:

通话活动:

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

新class级代码:

  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); } } 

所以我想我发表的所有这一切都是为了澄清,如果你想做上面的海报build议,你不能只是new()一个活动,并调用showAsPopup()。 这可能是我对Android的经验不足,虽然这看起来有点明显,但将showAsPopup()解释为由当前视图调用,而不是正在创build的视图是自然的,因为您正在传递活动实例(如果它本来应该在onCreate()中完成,就像我最终做的那样)。

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

再次,如果有一个简单/更好的方法来做到这一点,我将非常感激反馈。 希望这对那些想要使用这种方法的人有所帮助。

我花了大量的时间玩这个。 被接受的答案在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。 正确的解决scheme是通过setLayout来设置窗口的宽度,而不是使用setAttributes。

这是一个showAsPopup()的固定版本,它适用于我已经testing过的所有设备:

 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> 

像Veeti暗示的,你可能想尝试用对话主题实现一个活动。 在Android Manifest中:

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

希望这会有所帮助。

我可能不那么有经验,但我会使用一个活动,添加操作栏项目,然后:

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

希望有所帮助!

我知道这不是真正的答案,但上面的解决scheme看起来如此不雅,以至于人们会认为避免操作栏会更容易一些,比如从.noActionBarinheritance对话框主题,然后在面板顶部创build视图那模仿行动吧,至less这样的方式都留在xlm。

我find了一个很好的方法,在DialogFragment的alertDialog的构build器上使用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(); } 

结果(从我的应用程序 ):

在这里输入图像说明

在这里输入图像说明

如果你不想使用AlertDialog,你仍然可以把一个工具栏放到对话框的布局中并使用它。