如何使AppBarLayout背景透明化

11

我正在尝试制作一个类似于Play商店的搜索片段:

Google Play Store

我的AppBarLayout中有一个CardView,并且背景设置为透明:

<android.support.design.widget.CoordinatorLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/transparent"
        android:theme="@style/ThemeOverlay.AppCompat.ActionBar"
        app:elevation="0dp">

        <!-- CardView -->

    </android.support.design.widget.AppBarLayout>

    <android.support.v4.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="vertical"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <!-- Main content -->

    </android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>

但是,正如您所看到的,CardView后面有一个实心背景,因此它后面的内容被隐藏了:

Hidden content

我该如何使AppBarLayout的背景变为透明,以便它后面的内容可见?


您是否希望NestedScrollView在AppbarLayout下滚动? - jayeshsolanki93
我希望NestedScrollView的内容紧贴搜索区域,但现在在搜索区域上方没有任何内容可见,在下方有一条灰色线将搜索区域与内容分隔开。 编辑:是的,这就是我想要的。 - joharei
尝试在AppbarLayoutNestedScrollView中添加android:fitsSystemWindows="true" - jayeshsolanki93
这会在搜索区域下方创建更多的空白,滚动行为也会变得奇怪。 - joharei
4个回答

10

另一种选择是给NestedScrollView(或者使用appbar_scrolling_view_behavior的任何视图)添加负上边距,然后给其直接子项添加相同的正上边距(或填充):

另一个选项是为 NestedScrollView(或使用 appbar_scrolling_view_behavior 的任何视图)添加负的顶部边距,并为其直接子元素添加相同的正的顶部边距(或填充):

<androidx.core.widget.NestedScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    android:layout_marginTop="-100dp" >

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingTop="100dp" >

        ...

    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.core.widget.NestedScrollView>

<com.google.android.material.appbar.AppBarLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@null" >

    <com.google.android.material.appbar.CollapsingToolbarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_scrollFlags="scroll|exitUntilCollapsed" >

        ...

    </com.google.android.material.appbar.CollapsingToolbarLayout>

</com.google.android.material.appbar.AppBarLayout>

请注意,为了使这种方法起作用,AppBarLayout应该放在布局文件中NestedScrollView的下方。如果NestedScrollView的淡出边缘产生视觉伪影,请将android:overScrollMode="never"添加到其参数中。此外,在使用elevation时要小心,因为如果在错误的位置使用(比如应用于整个AppBarLayout),它也可能产生视觉伪影。


这应该是被接受的答案,完美地工作。 - edp

7
同样的问题也发生在我身上,目前这与AppBarLayout的透明度无关。但是当AppBarLayout淡入时,它会将你的NestedScrollView的内容推到自己的下方。
您可以通过以下方法解决此问题:
  1. 将您的NestedScrollView上移并置于AppBarLayout后面;
  2. NestedScrollView添加一个大小等于AppBar的空间元素。
步骤1很容易通过在onCreate()中添加以下内容来实现:
mNestedScroll.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        mNestedScroll.getViewTreeObserver().removeOnGlobalLayoutListener(this);

        final int appBarHeight = mAppBar.getHeight();
        mNestedScroll.setTranslationY(-appBarHeight);
        mNestedScroll.getLayoutParams().height = mNestedScroll.getHeight() + appBarHeight;
    }
});

2步需要在您的NestedScrollView中添加一个高度与appBar相同的空视图作为间隔。注意:我在我的方法中使用了RecyclerView而不是NestedScrollView,所以我不得不在我的RecyclerView中添加一个具有appBarHeight的空ViewHolder。因此,这段代码没有经过测试,但它应该能够帮助您完成任务:

<View
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"/>

这个修复方法很好地解决了问题。谢谢!然而,您描述的另一个问题仍然存在,即“snap”行为会将“NestedScrollView”内容向下推。您能否使用此解决方法来解决这个问题? - joharei
@joharei 抱歉,我不太明白你的问题。我描述的问题是所有内容都将绘制在 AppBarLayout 下方,使得 AppBarLayout 独占其所占用的空间。因此,可滚动的内容会显示在 AppBar 下方。我描述了两个步骤来克服这个缺点。第一步将把内容移动到 AppBar 下方并解决整个问题。第二步仅是将可滚动的内容对齐回正常位置(可能不需要您的实现)。 - Stefan Medack
我可能误解了,所以请忽略我的先前评论。不过,我对你的解决方案有问题。如果NestedScrollView中的内容比屏幕更高,当活动加载时,它将出现在AppBarLayout后面并向上滚动。当我开始滚动时,一切都表现得很好。 - joharei
@joharei 好的,听起来对我来说第二步似乎没有正确工作。我只能猜测,但可能是步骤2中的间隔视图太小,或者你在滚动视图中奇怪地居中对齐了你的内容(例如,将其居中)。您可以尝试增加在Step 2中添加的视图的layout_height来解决问题。 - Stefan Medack

0

尝试将CardView放入一个FrameLayout中,使用match_parent的尺寸,这样CardView周围就有空间了。我并不100%确定它会起作用,但值得一试。


我实际上已经在它周围放置了一个FrameLayout来调整一些填充。不幸的是,它并没有起作用。 - joharei

0

我尝试了很多代码,以给出更多或少你所寻找的东西。这是一种替代方案,但你需要将AppBarLayout更改为简单视图...看看这个:

<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/annonce.main.coordinator"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:ignore="RtlHardcoded">

<android.support.v7.widget.RecyclerView
    android:id="@+id/rv"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

<!-- here you put your search bar, can be any view !-->
<android.support.v7.widget.CardView
    android:id="@+id/searchbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:cardElevation="4dp"
    app:cardUseCompatPadding="true"
    app:layout_behavior="[package].RecyclerSearchBehavior">

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:hint="Pesquise aqui"
        android:minHeight="58dp"/>

</android.support.v7.widget.CardView>

注意:这是在CoordinatorLayout内部。 创建一个Behavior,其中视图是您正在使用的搜索栏的类型:
public class RecyclerSearchBehavior extends CoordinatorLayout.Behavior<CardView> {
//Initial height and location
private int mViewHeight;
private int[] mViewStartLocation;


public RecyclerSearchBehavior(Context context, AttributeSet attrs) {
}

@Override
public boolean layoutDependsOn(CoordinatorLayout parent, final CardView child, View dependency) {
    //the first function called. The initial variables settings.
    //getting height 
    mViewHeight = child.getHeight();
    //getting location on screen
    mViewStartLocation = new int[2];
    child.getLocationOnScreen(mViewStartLocation);
    //if the dependecy is your recycler
    if (dependency instanceof RecyclerView)
        //add scroll listener
        ((RecyclerView) dependency).addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
            }
            //here the magic happens
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                //animate function
                animate(child, dy);
            }
        });
    return dependency instanceof RecyclerView;
}

private void animate(CardView child, int dy) {
    //the initial position of your search bar is 0, because it is on top, so...
    if (child.getY() <= 0)
        //dy is an integer that shows you if user scrolls up or down
        if (dy >= 0) {
            //move to top is a negative value, so *-1
            //if that is < than height, scrools up
            if ((child.getY() * -1) <= (mViewHeight))
                child.setTranslationY(child.getY() - dy * 0.1f);
        } else {
            //if the position of search bar is < than zero, scrolls down
            if (child.getY() < 0)
                child.setTranslationY(child.getY() - dy * 0.1f);
            //else, put the view on 0y
            else child.setY(0);
        }
    //else, put the view on 0y again. this function is called after any user                    
    //touches... so everything happens fast and with numbers different than 
    //1 
    else child.setY(0);
}

}

完成了。你的“搜索栏”已经在这里。

唯一的问题是,你需要给Recycler的第一个项目添加填充,或者作为第一个项目的透明视图。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接