在Android上使用背景幕 [英] Using backdrop on Android

查看:72
本文介绍了在Android上使用背景幕的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

https://material.io/design/components/backdrop.html

我在Material Design上找到了这个,但是找不到任何资源. 考虑其布局,我认为它是由具有物料卡视图的任何布局组成的,并且我正尝试使用布局+物料卡视图来制作我的活动文件.这种方法是否正确进行背景布局?

I found this on Material Design, but couldn't find any resources. Thinking about its layout, I think it's made up of any layout with material card view, and I am trying to make my activity file using layout + material card view. Is this method correct to make backdrop layout?

此外,我想知道应该使用哪种布局.是RelativeLayout可以的方式吗?我真的不明白.

Also, I want to know about which layout I should use. Is RelativeLayout can be the way? I don't get it actually.

推荐答案

该组件(BackDrop)仍在为

This component (BackDrop) is still under development for the Android Material Components library as of 16 December 2018.

但是,如果您已经在使用Material Components,则实现自己的组件并不难.您将需要以下内容:

However, if you are using Material Components already, it's not that hard to implement your own. You will need the following:

  • CoordinatorLayout as the root layout
  • a BottomSheetBehaviour applied to an immediate child of the root layout

下面提供的解决方案,如下图所示……

The provided solution below, looks like the following image...

下面的示例使用一个片段,我将省略托管活动的详细信息,因为它与问题/答案无关.但是,您可以对活动执行完全相同的操作.您的片段布局文件将如下所示...

The example below uses a fragment, I'll ommit the details of the hosting activity because it is irrelevant to the question/answer. However, you can do exactly the same with an activity. Your fragment layout file will look like below...

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
    android:id="@+id/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:layout_width="match_parent"
    android:layout_height="match_parent">

    <!--This the interface sitting behind the backdrop and shown when it is collapsed-->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:background="@color/colorPrimary"
        android:padding="@dimen/activity_spacing">

        <EditText
            android:id="@+id/searchTextView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:drawableStart="@drawable/ic_search_primary_xlight_24dp"
            style="@style/EditTextStyle.Inverse.Large.Light"
            android:hint="@string/search_hint"/>

        <EditText
            android:id="@+id/datesFilterButton"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:drawableStart="@drawable/ic_calendar_primary_xlight_24dp"
            style="@style/EditTextStyle.Inverse.Large.Light"
            android:hint="@string/select_dates_hint"/>
    </LinearLayout>

    <!--This is the backdrop's content with a BottomSheetBehaviour applied to it-->
    <LinearLayout
        android:id="@+id/contentLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:behavior_peekHeight="56dp"
        app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">

        <!--This is the backdrop's header with a title and icon-->
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:clickable="true"
            android:background="@drawable/ic_list_header_background"
            android:padding="@dimen/activity_spacing"
            android:elevation="4dp">

            <TextView
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                style="@style/TextAppearance.Stems.Body2"
                android:text="0 items(s)"/>

            <ImageView
                android:id="@+id/filterIcon"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/ic_filter_black_24dp"
                android:layout_gravity="end"/>

        </LinearLayout>

        <!--And finally this is the body of the backdrop's content. You can add here whatever you need inside a view group (LinearLayout, RelativeLayout, SwipeRefreshLayout, ConstraintLayout, etc.)-->
        <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
            android:id="@+id/swiperefresh"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/colorBackground">

             <!--The content's body goes here-->
        </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

    </LinearLayout>   


</androidx.coordinatorlayout.widget.CoordinatorLayout>

在这里需要注意几件事.首先,位于背景后面的LinearLayout使用colorPrimary颜色与Toolbar的背景颜色完全相同...为清楚起见,省略了工具栏,它在托管活动中声明(记住,这个解决方案是针对碎片的.

There's a couple of things you need to be aware of here. First, the LinearLayout that sits behind the backdrop its using the colorPrimary color which exactly the same as the Toolbar's background color...the toolbar has been ommitted for clarity, it is declared in the hosting activity (remember, this solution is for a fragment).

然后片段的类将如下所示……

Then the fragment's class will look like this...

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

        coordinatorLayout = (CoordinatorLayout)inflater.inflate(R.layout.fragment_hazards, container, false);

        Context context = getContext();

        if(context != null){
            setTitle(context.getString(R.string.title_hazards));
        }

        filterIcon = coordinatorLayout.findViewById(R.id.filterIcon);
        LinearLayout contentLayout = coordinatorLayout.findViewById(R.id.contentLayout);

        sheetBehavior = BottomSheetBehavior.from(contentLayout);
        sheetBehavior.setFitToContents(false);
        sheetBehavior.setHideable(false);//prevents the boottom sheet from completely hiding off the screen
        sheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);//initially state to fully expanded

        filterIcon.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                toggleFilters();
            }
        });


        return coordinatorLayout;
    }

    private void toggleFilters(){
        if(sheetBehavior.getState() == BottomSheetBehavior.STATE_EXPANDED){
            sheetBehavior.setState(BottomSheetBehavior.STATE_HALF_EXPANDED);
        }
        else {
            sheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
        }
    }

就是这样,您唯一需要记住的是根布局必须是CoordinatorLayout,并且BottomSheetBehaviour必须应用于根布局的直接子项

And that's it, the only thing you need to keep in mind is that root layout has to be a CoordinatorLayout and that the BottomSheetBehaviour has to be applied to an immediate child of the root layout

您还将注意到,我没有在BackDrop标题中使用CardView来获得CardView随附的漂亮圆角.那是因为我只需要对顶部的角进行四舍五入,而CardView的默认实现不允许您显式设置各个角.相反,我使用了一个很好的旧LinearLayout并为其背景(ic_list_header_background)提供了我自己的可绘制对象.这是此drawable的xml声明...

You will also notice that I'm not using a CardView in the BackDrop's header to get the nice rounded corners the CardView comes with. That's because I only need the top corners to be rounded and the default implementation of CardView doesn't allow you to explicitly set individual corners. Instead, I used a good old LinearLayout and provided my own drawable for its background (ic_list_header_background). Here's the xml declaration of this drawable...

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">

    <solid android:color="@color/colorBackground" />
    <corners android:topLeftRadius="16dp" android:topRightRadius="16dp" />

</shape>

没有什么特别的,只是带有选择性圆角(顶部)的矩形

Nothing really fancy, just a rectangular shape with selective rounded corners (the top ones)

您将要删除工具栏的投影,可以将其标高设置为0dp或以编程方式删除父级AppBarLayout上的轮廓提供程序,如下所示...

You will want to remove the ToolBar's drop shadow, to do so, you can set its elevation to 0dp or programmatically remove the outline provider on the parent AppBarLayout as below...

appBarLayout.setOutlineProvider(null);

很明显,这是假设您的Toolbar根据指南位于AppBarLayout之内

obviously, this is assuming that your Toolbar is inside an AppBarLayout as per the guidelines

我希望这在Material Component的BackDrop仍在开发中时确实能对那里的人有所帮助.这不是完美的,因为您仍然受限于BottomSheetBehaviour组件所公开的功能,该功能非常有限.但是,如果您挑剔或想花哨,我建议通过扩展默认的BottomSheetBehaviour来实现自己的BottomSheetBehaviour.

I hope this really helps someone out there while the Material Component's BackDrop is still under development. It's not perfect because you are still bound to the functionalities exposed by the BottomSheetBehaviour component that it's quite limited. But if you are picky or want to go fancy, I'd recommend implementing your own BottomSheetBehaviour by extending the default one

基于材料设计指南,建议不要使用滑动手势在背景的最上层

Based on Material Design Guidelines, it is recommended not to use swipe gestures on the front layer of the backdrop

请勿使用前一层的滑动手势来显示后一层.

Don’t use the swipe gesture on the front layer to reveal the back layer.

但是,默认情况下,BottomSheetBehaviour不会公开任何属性或API来禁用滑动手势.为此,您将需要扩展覆盖所有与手势相关的方法的BottomSheetBehaviour来实现自己的方法.这是我在一个项目(用Kotlin编写)中使用的示例

However, by default, the BottomSheetBehaviour doesn't expose any properties or APIs to disable swipe gestures. To achieve that, you will need to implement your own by extending the BottomSheetBehaviour overriding all gesture-related methods. Here's an example I'm using in one of my projects (written in Kotlin)

class GestureLockedBottomSheetBehavior<V: View>(context: Context, attributeSet: AttributeSet?) : BottomSheetBehavior<V>(context, attributeSet){

    constructor(context: Context):this(context, null)

    override fun onInterceptTouchEvent(parent: CoordinatorLayout, child: V, event: MotionEvent): Boolean = false

    override fun onTouchEvent(parent: CoordinatorLayout, child: V, event: MotionEvent): Boolean = false

    override fun onStartNestedScroll(
        coordinatorLayout: CoordinatorLayout,
        child: V,
        directTargetChild: View,
        target: View,
        axes: Int,
        type: Int
    ): Boolean = false

    override fun onNestedPreScroll(
        coordinatorLayout: CoordinatorLayout,
        child: V,
        target: View,
        dx: Int,
        dy: Int,
        consumed: IntArray,
        type: Int
    ) { }

    override fun onStopNestedScroll(coordinatorLayout: CoordinatorLayout, child: V, target: View, type: Int) { }

    override fun onNestedFling(
        coordinatorLayout: CoordinatorLayout,
        child: V,
        target: View,
        velocityX: Float,
        velocityY: Float,
        consumed: Boolean
    ): Boolean = false
}

即使您不熟悉Kotlin,也不难发现我正在做的就是重写方法上的一堆,并通过不调用超类的对应对象而返回false或不做任何事情

Even if you're not familiar with Kotlin it shouldn't be hard to figure out that all I'm doing is overriding a bunch on methods and return false or doing nothing by not calling the super class's counterpart

然后使用此GestureLockedBottomSheetBehavior类,您将需要按如下所示在其布局中替换它...

Then to use this GestureLockedBottomSheetBehavior class, you will need to replace it in your layout as below...

<LinearLayout
        android:id="@+id/contentLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:behavior_peekHeight="56dp"
        app:layout_behavior="ui.behaviors.GestureLockedBottomSheetBehavior">
...
</LinearLayout>

只需确保根据您的自定义类所在的包设置了完全限定的名称.

Just make sure the fully-qualified name is set according to the package your custom class resides in.

这篇关于在Android上使用背景幕的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆