【问题标题】:display view on top of action bar在操作栏顶部显示视图
【发布时间】:2013-02-23 03:36:48
【问题描述】:

有没有办法在操作栏顶部呈现视图?我想创建一个小提示框,将用户指向操作栏中的项目。我知道带有设置视图的Toast 将呈现在操作栏上方。有谁知道如何使用视图来执行此操作?

我曾尝试将FrameLayoutlayout_gravity="top" 一起使用并膨胀视图,然后将其添加到正在运行的活动的布局中。

我提前感谢您。

编辑: 这是我在想的图像:

编辑: 也许需要更多细节。我正在寻找一种方法,或者找出是否可以将视图添加到活动的视图层次结构中,以便最后呈现。

与 CSS 类似,我希望此特定视图(图像中的蓝色浮动框)具有更高的 z-index 顺序,以便将其呈现在活动中的操作栏区域的顶部。视图与 Action Bar 没有任何关联,它只是简单地绘制在它上面。

【问题讨论】:

  • 您找到解决此问题的方法了吗?我现在想在我的应用中执行相同的任务,但我在下面没有看到任何相关答案。
  • @MM 看看我的回答。刚刚添加。

标签: android view android-actionbar z-index


【解决方案1】:

我试图实现其他目标,但我需要一个与此类似的解决方案。我需要绘制一个覆盖整个屏幕的不透明层,甚至是操作栏——有点像对话框。我是这样做的:

ViewGroup vg = (ViewGroup)(getWindow().getDecorView().getRootView());
vg.addView(myNewView, params);

这可用于在屏幕上的任何位置绘制任何内容。

更新:您真的不应该再使用 ActionBar,如果您像 Android 推荐的那样使用 Toolbar,您一开始就不会遇到这个问题。工具栏会像常规视图一样进入您的活动 xml,您可以对其进行任何操作。并且它完全向后兼容。 https://developer.android.com/training/appbar/setting-up

【讨论】:

  • @ekashking params 是一个 LayoutParams 实例。它用于确定您的视图将如何布局。例如new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)
【解决方案2】:

在我自己挣扎了一段时间之后,这是解决方案(经过测试 - 效果很好):

一般步骤是:

  1. 创建包装视图
  2. 分离屏幕视图子项、放置包装器并附加子项
  3. 向孩子们夸大内容
  4. 控制包装器将帮助您完全控制操作栏及其下方的内容。
  5. 现在,您可以使用包装器将“兄弟”添加到操作栏/主区域。那位兄弟正是您在图片中所描述的。

让我们看一些代码。

首先,创建一个方法来帮助创建包装视图。包装器将放置在整个屏幕和应用内容之间。作为ViewGroup,您以后可以完全控制它的内容。

private ViewGroup setContentViewWithWrapper(int resContent) {
        ViewGroup decorView = (ViewGroup) this.getWindow().getDecorView();
        ViewGroup decorChild = (ViewGroup) decorView.getChildAt(0);

        // Removing decorChild, we'll add it back soon
        decorView.removeAllViews();

        ViewGroup wrapperView = new FrameLayout(this);

        // You should set some ID, if you'll want to reference this wrapper in that manner later
        //
        // The ID, such as "R.id.ACTIVITY_LAYOUT_WRAPPER" can be set at a resource file, such as:
        //  <resources xmlns:android="http://schemas.android.com/apk/res/android">
        //      <item type="id" name="ACTIVITY_LAYOUT_WRAPPER"/>
        //  </resources>
        //
        wrapperView.setId(R.id.ACTIVITY_LAYOUT_WRAPPER);

        // Now we are rebuilding the DecorView, but this time we 
        // have our wrapper view to stand between the real content and the decor
        decorView.addView(wrapperView, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        wrapperView.addView(decorChild, decorChild.getLayoutParams());
        LayoutInflater.from(this).inflate(getActivityLayout(), 
                    (ViewGroup)((LinearLayout)wrapperView.getChildAt(0)).getChildAt(1), true);

        return wrapperView;
    }

现在,干扰常规的Activity 创建,而不是使用setContentView,而是使用我们创建的方法。

    @Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // DON'T CALL `setContentView`, 
    // we are replacing that line with this code:
    ViewGroup wrapperView = setContentViewWithWrapper(R.layout.activity_layout);

    // Now, because the wrapper view contains the entire screen (including the notification bar
    // which is above the ActionBar) I think you'll find it useful to know the exact Y where the 
    // action bar is located.
    // You can use something like that:
    ViewGroup actionBar = (ViewGroup)((LinearLayout)wrapperView.getChildAt(0)).getChildAt(0);
    int topOffset = actionBar.getTop();

    // Now, if you'll want to add a view:
    //  1. Create new view
    //  2. Set padding top - use "topOffset"
    //  3. Add the view to "wrapperView"
    //  4. The view should be set at front. if not - try calling to "bringToFront()"
}

就是这样。

注意事项

  • 我使用Android's hierarchy-viewer 来了解什么是正确的层次结构。 (没猜到那些 01 索引)
  • 如果您在 Activity 中使用某种菜单抽屉,则可能需要对其进行稍微不同的配置,因为抽屉已经为您创建了该包装器
  • 看了this great library我学到了很多

编辑:请参阅@CristopherOyarzúnAltamirano 回答以获得对较新 Android 版本的进一步支持

祝你好运!

【讨论】:

  • 嘿伙计。我在为 android 4.4 实现这个解决方案时遇到了一些问题。我有这个例外,有什么想法吗? com.android.internal.widget.ActionBarOverlayLayout 无法转换为 android.widget.LinearLayout。
  • 这适用于 ICS 和 Jelly,但 Ginger 和 Kitkat 以不同的方式绘制层次结构。
  • 如果我使用的是 SlidingUpPanelLayout,我该如何配置它?我得到一个 java.lang.IllegalStateException: Height must have a exact value or MATCH_PARENT at com.sothree.slidinguppanel.SlidingUpPanelLayout.onMeasure(SlidingUpPanelLayout.java:386) 所以在容器视图的某个阶段它没有 MATCH_PARENT 值为高度。有趣的是,它不会抱怨宽度。
  • 我收到 ClassCastException Caused by: java.lang.ClassCastException: android.view.ViewStub cannot be cast to android.view.ViewGroup
  • 该答案应该更新。导致“强制关闭”。
【解决方案3】:

有一种更简单的方法可以实现这一点。 ActionBar 将其布局保存在类 ActionBarContainer 中,该类仅继承自 FrameLayout。因此,为了在 ActionBar 上显示某些内容,您需要获取对 ActionBarContainer 的引用并将您自己的自定义 View 添加到其中。这是代码

    int abContainerViewID = getResources().getIdentifier("action_bar_container", "id", "android");     
    FrameLayout actionBarContainer = (FrameLayout)findViewById(abContainerViewID);      
    LayoutInflater myinflater = getLayoutInflater();        
    View customView = myinflater.inflate(R.layout.yourCustomeViewLayout, null);
    actionBarContainer.addView(customView);

【讨论】:

  • 不适合我。甚至 actionb_bar_container 也在视图层次结构中。 actionBarContainer 为空。
【解决方案4】:

我根据@Sean 的回答找到了这个解决方法:

        //This is for Jelly, ICS, Honeycomb
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB && Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2){
            LayoutInflater.from(this).inflate(resContent, (ViewGroup)((LinearLayout)wrapperView.getChildAt(0)).getChildAt(1), true);}
        //This is for KitKat and Jelly 4.3
        else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2){
            LayoutInflater.from(this).inflate(resContent, (ViewGroup) (((ViewGroup) wrapperView.getChildAt(0)).getChildAt(0)), true);}
        //This is for Ginger
        else{
            LayoutInflater.from(this).inflate(resContent, (ViewGroup) ((LinearLayout)((FrameLayout) wrapperView.getChildAt(0)).getChildAt(0)).getChildAt(1), true);}

【讨论】:

  • 我在 Gingerbird 设备上使用此方法时出错。我这样编辑它: LayoutInflater.from(this).inflate(resContent, (ViewGroup) ((FrameLayout) decorChild), true);
【解决方案5】:

我找到了一种更简单的方法来做到这一点。 我刚刚将 android:translationZ="10dp" 应用于需要覆盖操作栏的视图。

我选择了 10dp,但它实际上可以是任何你想要的,只要它优于操作栏的高度

<ImageView
      android:layout_width="100dp"
      android:layout_height="100dp"
      android:translationZ="10dp"
      android:src="@drawable/potatoe" />

另外,不要担心 Android Studio 的以下警告:

“translationZ 不能与 API

它将被忽略,但您并不在意,因为工具栏不应该使用低于 21 的 API 覆盖您的视图。

【讨论】:

  • 不起作用。imageView 仍会在应用栏后面
【解决方案6】:

尝试使用 ActionBar.setCustomView()。这是更改屏幕该区域外观的唯一方法。您不能将 View 粘贴到 ActionBar“上方”的区域中,因为该区域基本上由系统控制。另一方面,您可以为其提供自己的布局。

如果您更详细地解释您想要做什么,受访者可能会有一些更好的设计理念。

【讨论】:

  • 酷,我已经包含了我在想什么的图像。我看到 Toasts 可以有一个视图集。我很想知道他们如何将视图呈现在操作栏的顶部。
【解决方案7】:

https://github.com/michaelye/EasyDialogDemo

看上面的demo,可能对你有帮助

dialog.setLocation(new location[])//point in screen

您可以自己设置位置[]。

【讨论】:

    【解决方案8】:

    在 menu.xml 文件中使用android:actionLayout

    <?xml version="1.0" encoding="utf-8"?><menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/menu_id"
          android:title="@string/menu_string_to_show"
          android:icon="@drawable/ic_menu_icon_name"
          android:showAsAction="always"
          android:actionLayout="@layout/action_button_foo" /></menu>
    

    然后创建你的 action_button_foo.xml 布局:

    <?xml version="1.0" encoding="utf-8"?><TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:text="@string/menu_string_to_show"
    android:drawableLeft="@drawable/ic_menu_icon_name"
    android:background="@drawable/bg_btn_action_bar"
    android:clickable="true" />
    

    要处理点击,请执行以下操作:

    @Overridepublic boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.my_menu, menu);
    
    final MenuItem item = menu.findItem(R.id.menu_id);
    item.getActionView().setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            onOptionsItemSelected(item);
        }
    });
    
    return super.onCreateOptionsMenu(menu);}
    

    如果:)

    【讨论】:

    • 感谢您的快速回复!但我相信这是为操作栏创建一个菜单项?我只想在操作栏的顶部绘制一个视图。但是这个视图不应该是操作栏的一部分,它是无响应的。
    • 视图是什么意思?
    • 它将是布局文件和图像背景中的 TextView。如果您在我的 OP 中查看添加的图像,那将是浮动的蓝色框
    【解决方案9】:

    (参考:http://www.vogella.com/articles/AndroidActionBar/article.html
    ActionBar 中的自定义视图
    您还可以向ActionBar 添加自定义视图。为此,您对ActionView 类使用setCustomView 方法。您还必须通过setDisplayOptions() 方法通过传入ActionBar.DISPLAY_SHOW_CUSTOM 标志来启用自定义视图的显示。

    例如,您可以定义一个包含EditText 元素的布局文件。

    <?xml version="1.0" encoding="utf-8"?>
    <EditText xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/searchfield"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:inputType="textFilter" >
    

    可以通过以下代码将此布局分配给ActionBar。示例代码允许将侦听器附加到自定义视图。

    package com.vogella.android.actionbar.customviews;
    
    import android.app.ActionBar;
    import android.app.Activity;
    import android.os.Bundle;
    import android.view.KeyEvent;
    import android.widget.EditText;
    import android.widget.TextView;
    import android.widget.TextView.OnEditorActionListener;
    import android.widget.Toast;
    
    public class MainActivity extends Activity {
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    
    ActionBar actionBar = getActionBar();
    // add the custom view to the action bar
    actionBar.setCustomView(R.layout.actionbar_view);
    EditText search = (EditText) actionBar.getCustomView().findViewById(R.id.searchfield);
    search.setOnEditorActionListener(new OnEditorActionListener() {
    
      @Override
      public boolean onEditorAction(TextView v, int actionId,
          KeyEvent event) {
        Toast.makeText(MainActivity.this, "Search triggered",
            Toast.LENGTH_LONG).show();
        return false;
      }
    });
    actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM
        | ActionBar.DISPLAY_SHOW_HOME);
    }
    } 
    

    【讨论】:

    • 啊,好吧,据我了解,当我单击操作栏时,您正在添加一个Toast 通知,特别是EditText。我想知道更多关于如何在操作栏顶部直观地呈现视图/布局。就像我知道 Android 如何创建视图层次结构一样。如何插入要在层次结构中最后呈现的视图,使其在 z-index 排序或“将视图置于前面”的意义上显示在操作栏“上方”。或者甚至有可能吗?无论如何,感谢您的帮助 Vishal。
    • 所以你告诉你必须在操作栏上插入一个自定义视图而不使用 setCustomView。我认为您必须转到自定义操作栏。
    • 最好使用自定义操作栏(创建自己的操作栏)。你可以用它做任何你想做的事情。
    • 从github下载actionbar sherlock,看看他们是如何实现action bar的。
    【解决方案10】:

    这里的解释都太长了:

    将主布局文件包装到顶级 ViewGroup 中(例如,将 CoordinatorLayout 包装到 FrameLayout 中),然后在新的顶级布局中注入或声明视图。该视图将出现在操作栏上方。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-05
      • 1970-01-01
      • 1970-01-01
      • 2023-04-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多