在操作栏顶部显示视图

lun*_*aps 37 android view z-index android-actionbar

有没有办法在操作栏上呈现视图?我想创建一个小的提示框,将用户指向操作栏中的项目.我知道Toast具有设定视图的a将呈现在操作栏上方.有谁知道如何用视图做到这一点?

我已经尝试使用FrameLayoutlayout_gravity="top"和膨胀视图,然后将其添加到运行活动的布局.

我提前感谢你.

编辑:这是我在想的图像: 在此输入图像描述

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

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

Sia*_*ash 33

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

ViewGroup vg = (ViewGroup)(getWindow().getDecorView().getRootView());
vg.addView(myNewView, params);
Run Code Online (Sandbox Code Playgroud)

这可以用来在屏幕上的任何地方绘制任何东西.


Sea*_*ean 22

经过很长一段时间的努力,这是解决方案(测试它 - 工作良好):

一般步骤是:

  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;
    }
Run Code Online (Sandbox Code Playgroud)

现在,干扰常规的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()"
}
Run Code Online (Sandbox Code Playgroud)

就是这样.

笔记

  • 我已经使用Android的层次结构查看器来理解什么是正确的层次结构.(没想到那些01索引)
  • 如果您在活动中使用某种菜单抽屉,则可能需要将其配置略有不同,因为抽屉已经为您创建了包装器
  • 通过查看这个伟大的图书馆,我学到了很多东西

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

祝好运!

  • 这对ICS和Jelly起作用,但Ginger和Kitkat以不同的方式绘制层次结构. (2认同)

Nou*_*nif 15

有一种更简单的方法来实现这一目标.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);
Run Code Online (Sandbox Code Playgroud)


Cri*_*ano 5

我找到了基于@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);}
Run Code Online (Sandbox Code Playgroud)


Jac*_*ck' 5

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

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

<ImageView
      android:layout_width="100dp"
      android:layout_height="100dp"
      android:translationZ="10dp"
      android:src="@drawable/potatoe" />
Run Code Online (Sandbox Code Playgroud)

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

“translationZ 不能与 API<21 一起使用”。

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