简体   繁体   中英

Blur Surrounding Of Expanded RecyclerView Item (Blur RecyclerView Except Of One Of Its Items)

I have a RecyclerView containing its children:

在此处输入图片说明

As you can see in the picture, each item can be expanded (for example item i in the picture). In my project I use this blur library to blur things, for example, clicking the FloatingActionButton expands it to a dialog, and the dialog's surrounding is blurred, like this:

在此处输入图片说明

I want that an expanded RecyclerView s item will have its surrounding blurred as well. I tried this:

( Item.xml :)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <com.github.mmin18.widget.RealtimeBlurView
        android:id="@+id/blur_view_per_active_goal_card"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        app:realtimeBlurRadius="20dp"
        app:realtimeOverlayColor="#8000"
        android:visibility="visible"/>

    <androidx.cardview.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        app:cardCornerRadius="15dp"
        app:cardElevation="10dp">

        <RelativeLayout
            android:id="@+id/root_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <LinearLayout
                android:id="@+id/active_goal_card"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_margin="4dp"
                android:orientation="horizontal"
                android:padding="10dp"
                android:weightSum="10">

                <com.example.performancemeasurement.customViews.CustomProgressBar.CustomProgressBar
                    android:id="@+id/active_goal_item_progress_bar"
                    android:layout_width="0dp"
                    android:layout_height="50dp"
                    android:layout_weight="9"
                    android:transitionName="progressBar"
                    android:visibility="visible"
                    app:enable_gradient="true" />

                <ImageButton
                    android:id="@+id/active_goal_item_open_close_image_button"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="?attr/selectableItemBackground"
                    android:scaleType="fitCenter"
                    android:src="@drawable/down_vector" />

            </LinearLayout>

            <RelativeLayout
                android:id="@+id/expanded_active_goal_card"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_margin="4dp"
                android:visibility="gone">


                <TextView
                    android:id="@+id/expanded_active_goal_card_label"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_margin="10dp"
                    android:layout_centerHorizontal="true"
                    android:text="Goal Name"
                    android:textColor="@android:color/black"
                    android:textSize="40sp"
                    android:textStyle="bold" />


                <com.example.performancemeasurement.customViews.CustomProgressBar.CustomProgressBar
                    android:id="@+id/expanded_active_goal_card_progress_bar"
                    android:layout_width="wrap_content"
                    android:layout_height="30dp"
                    android:layout_below="@id/expanded_active_goal_card_label"
                    android:layout_alignParentStart="true"
                    android:layout_alignParentEnd="true"
                    android:layout_marginStart="20dp"
                    android:layout_marginEnd="20dp"
                    android:layout_centerHorizontal="true"
                    android:transitionName="progressBar"
                    app:enable_gradient="true" />

                <TextView
                    android:id="@+id/expanded_active_goal_card_description"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_below="@id/expanded_active_goal_card_progress_bar"
                    android:layout_centerHorizontal="true"
                    android:layout_margin="10dp"
                    android:maxLines="3"
                    android:text="Goal's Description"
                    android:textColor="#6F6F6F"
                    android:textSize="20sp"
                    android:textStyle="normal" />

                <LinearLayout
                    android:id="@+id/expanded_active_goal_card_sub_goals_label_container"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_below="@id/expanded_active_goal_card_description"
                    android:layout_centerHorizontal="true"
                    android:layout_margin="5dp"
                    android:gravity="center_vertical"
                    android:orientation="horizontal"
                    android:weightSum="14">

                    <View
                        android:id="@+id/expanded_active_goal_card_sub_goal_label_left"
                        android:layout_width="0dp"
                        android:layout_height="3dp"
                        android:layout_weight="4"
                        android:background="@color/light_gray" />

                    <TextView
                        android:id="@+id/expanded_active_goal_card_sub_goals_label"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_margin="5dp"
                        android:layout_weight="6"
                        android:gravity="center"
                        android:text="SubGoals"
                        android:textColor="#5A5A5A"
                        android:textSize="25sp"
                        android:textStyle="bold" />

                    <View
                        android:id="@+id/expanded_active_goal_card_sub_goal_label_right"
                        android:layout_width="0dp"
                        android:layout_height="3dp"
                        android:layout_weight="4"
                        android:background="@color/light_gray" />

                </LinearLayout>

                <RelativeLayout
                    android:id="@+id/expanded_active_goal_card_sub_goals_container"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_below="@+id/expanded_active_goal_card_sub_goals_label_container"
                    android:layout_centerHorizontal="true"
                    android:layout_margin="10dp"
                    android:animateLayoutChanges="true"
                    android:elevation="15dp"
                    android:gravity="center">

                    <androidx.recyclerview.widget.RecyclerView
                        android:id="@+id/expanded_active_goal_card_sub_goals_recycler_view"
                        android:layout_width="match_parent"
                        android:layout_height="100dp" />

                </RelativeLayout>

            </RelativeLayout>

        </RelativeLayout>

    </androidx.cardview.widget.CardView>


</RelativeLayout>

(putting the blurred view behind the item's content, and then in the RecyclerView s ViewHolder handle the blur visibility as I did in the Dialog example every time the item is expanded/shrunk, but even when I make it visible without handling it, the blur won't show. I tried to handle it programmatically as planned, but still, the blur didn't show up.

So the question is: Specifically in my case - where is the problem? Why won't the blur show? And in general... how can I blur the surrounding of a RecyclerView s expanded/focused item (using the RealtimeBlurView library or any other that suits the solution for this problem), or in other words, how can I blur the whole Recyclerview except of one of its items / how can I blur the background of specific View (blur everything except this View .

Help would be highly appreciated! (:

You must put RealtimeBlurView above another view to make that view blur but in your implementation, RealtimeBlurView is below CardView , so you can't see the Bure effect. You must put it after CardView in your layout file. Try the following code:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <androidx.cardview.widget.CardView
        android:id="@+id/cardView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        app:cardCornerRadius="15dp"
        app:cardElevation="10dp">

        <RelativeLayout
            android:id="@+id/root_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <LinearLayout
                android:id="@+id/active_goal_card"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_margin="4dp"
                android:orientation="horizontal"
                android:padding="10dp"
                android:weightSum="10">

                <com.example.performancemeasurement.customViews.CustomProgressBar.CustomProgressBar
                    android:id="@+id/active_goal_item_progress_bar"
                    android:layout_width="0dp"
                    android:layout_height="50dp"
                    android:layout_weight="9"
                    android:transitionName="progressBar"
                    android:visibility="visible"
                    app:enable_gradient="true" />

                <ImageButton
                    android:id="@+id/active_goal_item_open_close_image_button"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="?attr/selectableItemBackground"
                    android:scaleType="fitCenter"
                    android:src="@drawable/down_vector" />

            </LinearLayout>

            <RelativeLayout
                android:id="@+id/expanded_active_goal_card"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_margin="4dp"
                android:visibility="gone">


                <TextView
                    android:id="@+id/expanded_active_goal_card_label"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_margin="10dp"
                    android:layout_centerHorizontal="true"
                    android:text="Goal Name"
                    android:textColor="@android:color/black"
                    android:textSize="40sp"
                    android:textStyle="bold" />


                <com.example.performancemeasurement.customViews.CustomProgressBar.CustomProgressBar
                    android:id="@+id/expanded_active_goal_card_progress_bar"
                    android:layout_width="wrap_content"
                    android:layout_height="30dp"
                    android:layout_below="@id/expanded_active_goal_card_label"
                    android:layout_alignParentStart="true"
                    android:layout_alignParentEnd="true"
                    android:layout_marginStart="20dp"
                    android:layout_marginEnd="20dp"
                    android:layout_centerHorizontal="true"
                    android:transitionName="progressBar"
                    app:enable_gradient="true" />

                <TextView
                    android:id="@+id/expanded_active_goal_card_description"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_below="@id/expanded_active_goal_card_progress_bar"
                    android:layout_centerHorizontal="true"
                    android:layout_margin="10dp"
                    android:maxLines="3"
                    android:text="Goal's Description"
                    android:textColor="#6F6F6F"
                    android:textSize="20sp"
                    android:textStyle="normal" />

                <LinearLayout
                    android:id="@+id/expanded_active_goal_card_sub_goals_label_container"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_below="@id/expanded_active_goal_card_description"
                    android:layout_centerHorizontal="true"
                    android:layout_margin="5dp"
                    android:gravity="center_vertical"
                    android:orientation="horizontal"
                    android:weightSum="14">

                    <View
                        android:id="@+id/expanded_active_goal_card_sub_goal_label_left"
                        android:layout_width="0dp"
                        android:layout_height="3dp"
                        android:layout_weight="4"
                        android:background="@color/light_gray" />

                    <TextView
                        android:id="@+id/expanded_active_goal_card_sub_goals_label"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_margin="5dp"
                        android:layout_weight="6"
                        android:gravity="center"
                        android:text="SubGoals"
                        android:textColor="#5A5A5A"
                        android:textSize="25sp"
                        android:textStyle="bold" />

                    <View
                        android:id="@+id/expanded_active_goal_card_sub_goal_label_right"
                        android:layout_width="0dp"
                        android:layout_height="3dp"
                        android:layout_weight="4"
                        android:background="@color/light_gray" />

                </LinearLayout>

                <RelativeLayout
                    android:id="@+id/expanded_active_goal_card_sub_goals_container"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_below="@+id/expanded_active_goal_card_sub_goals_label_container"
                    android:layout_centerHorizontal="true"
                    android:layout_margin="10dp"
                    android:animateLayoutChanges="true"
                    android:elevation="15dp"
                    android:gravity="center">

                    <androidx.recyclerview.widget.RecyclerView
                        android:id="@+id/expanded_active_goal_card_sub_goals_recycler_view"
                        android:layout_width="match_parent"
                        android:layout_height="100dp" />

                </RelativeLayout>

            </RelativeLayout>

        </RelativeLayout>

    </androidx.cardview.widget.CardView>

    <com.github.mmin18.widget.RealtimeBlurView
        android:id="@+id/blur_view_per_active_goal_card"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignTop="@id/cardView"
        android:layout_alignBottom="@id/cardView"
        android:layout_alignLeft="@id/cardView"
        android:layout_alignRight="@id/cardView"
        app:realtimeBlurRadius="20dp"
        app:realtimeOverlayColor="#8000"
        android:visibility="visible"/>

</RelativeLayout>


Update
Since you need to blur other items except for expanded item, you should handle it in your adapter implementation. The following code snippet shows how to implement it.

MyAdapter.kt

class MyAdapter : RecyclerView.Adapter<MyAdapter.MyViewHolder>(), View.OnClickListener {

    val items = ArrayList<Item>()
    var expandedItemIndex = -1

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyAdapter.MyViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.layout_row, parent, false)
        return MyViewHolder(view, this)
    }

    override fun getItemCount() = items.size

    override fun onBindViewHolder(holder: MyAdapter.MyViewHolder, position: Int) {
        items.get(position)?.apply { holder.bind(this, expandedItemIndex) }
    }

    override fun onClick(v: View?) {
        v?.let {
            if(it.id == R.id.blur) {
                expandedItemIndex = -1
                notifyDataSetChanged()
            } else if(it.id == R.id.expand_btn) {
                val holder = it.getTag() as MyViewHolder
                if (expandedItemIndex == holder.adapterPosition) {
                    expandedItemIndex = -1;
                    notifyDataSetChanged()
                } else {
                    expandedItemIndex = holder.adapterPosition
                    notifyDataSetChanged()
                }
            }
        }
    }

    class MyViewHolder(itemView: View, onClickListener: View.OnClickListener) : RecyclerView.ViewHolder(itemView) {

        val textView : TextView = itemView.findViewById(R.id.text)
        val expandButton : ImageView = itemView.findViewById(R.id.expand_btn)
        val expandArea : View = itemView.findViewById(R.id.expanded_area);
        val blur : View = itemView.findViewById(R.id.blur);

        init {
            expandButton.setOnClickListener(onClickListener)
            blur.setOnClickListener(onClickListener)
        }

        fun bind(item: Item, expandedItemIndex: Int) {
            textView.text = item.value.toString()
            expandButton.setTag(this)
            if(expandedItemIndex >= 0) {
                blur.visibility = View.VISIBLE
                if(expandedItemIndex == adapterPosition) {
                    blur.z = -1f
                    expandArea.visibility = View.VISIBLE
                    expandButton.setImageResource(android.R.drawable.arrow_up_float)
                } else {
                    blur.z = 0f
                    expandArea.visibility = View.GONE
                    expandButton.setImageResource(android.R.drawable.arrow_down_float)
                }
            } else {
                expandArea.visibility = View.GONE
                blur.visibility = View.INVISIBLE
            }
        }
    }
}

layout_row.xml

<RelativeLayout 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="wrap_content"
    android:orientation="vertical">

    <FrameLayout
        android:id="@+id/cardHolder"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <androidx.cardview.widget.CardView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="5dp"
            app:cardCornerRadius="15dp"
            app:cardElevation="5dp">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical"
                android:padding="10dp">

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:gravity="center"
                    android:orientation="horizontal">

                    <TextView
                        android:id="@+id/text"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:text="Header Text" />

                    <ImageView
                        android:id="@+id/expand_btn"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:padding="8dp"
                        android:src="@android:drawable/arrow_down_float" />

                </LinearLayout>

                <LinearLayout
                    android:id="@+id/expanded_area"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical"
                    android:visibility="gone"
                    tools:visibility="visible">

                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:text="Expanded Line 1"></TextView>

                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:text="Expanded Line 2"></TextView>

                </LinearLayout>
            </LinearLayout>
        </androidx.cardview.widget.CardView>
    </FrameLayout>

    <com.github.mmin18.widget.RealtimeBlurView
        android:id="@+id/blur"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignTop="@+id/cardHolder"
        android:layout_alignBottom="@id/cardHolder"
        app:realtimeBlurRadius="20dp"
        app:realtimeOverlayColor="#8000" />
</RelativeLayout>

MyAdapterJava.Java (Java implementaion of adapter)

public class MyAdapterJava extends RecyclerView.Adapter<MyAdapterJava.MyViewHolder> implements View.OnClickListener{

    List<Item> items = new ArrayList<Item>();
    int expandedItemIndex = -1;

    @NonNull
    @Override
    public MyAdapterJava.MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_row, parent, false);
        return new MyViewHolder(view, this);
    }

    @Override
    public int getItemCount() {
        return items.size();
    }

    @Override
    public void onBindViewHolder(@NonNull MyAdapterJava.MyViewHolder holder, int position) {
        holder.bind(items.get(position), expandedItemIndex);
    }

    @Override
    public void onClick(View v) {
        if(v != null) {
            if(v.getId() == R.id.blur) {
                expandedItemIndex = -1;
                notifyDataSetChanged();
            } else if(v.getId() == R.id.expand_btn) {
                MyViewHolder holder = (MyViewHolder) v.getTag();
                if (expandedItemIndex == holder.getAdapterPosition()) {
                    expandedItemIndex = -1;
                    notifyDataSetChanged();
                } else {
                    expandedItemIndex = holder.getAdapterPosition();
                    notifyDataSetChanged();
                }
            }
        }
    }

    static class MyViewHolder extends RecyclerView.ViewHolder {

        TextView textView;
        ImageView expandButton;
        View expandArea;
        View blur;

        public MyViewHolder(View itemView, View.OnClickListener onClickListener) {
            super(itemView);

            textView = itemView.findViewById(R.id.text);
            expandButton = itemView.findViewById(R.id.expand_btn);
            expandArea = itemView.findViewById(R.id.expanded_area);
            blur = itemView.findViewById(R.id.blur);

            expandButton.setOnClickListener(onClickListener);
            blur.setOnClickListener(onClickListener);
        }

        public void bind(Item item, int expandedItemIndex) {
            textView.setText(String.valueOf(item.getValue()));
            expandButton.setTag(this);
            if(expandedItemIndex >= 0) {
                blur.setVisibility(View.VISIBLE);
                if(expandedItemIndex == getAdapterPosition()) {
                    blur.setZ(-1f);
                    expandArea.setVisibility(View.VISIBLE);
                    expandButton.setImageResource(android.R.drawable.arrow_up_float);
                } else {
                    blur.setZ(0f);
                    expandArea.setVisibility(View.GONE);
                    expandButton.setImageResource(android.R.drawable.arrow_down_float);
                }
            } else {
                expandArea.setVisibility(View.GONE);
                blur.setVisibility(View.INVISIBLE);
            }
        }
    }
}

The result will be like this: 在此处输入图片说明


PS:
1. Since this code is using View.SetZ(float) to handle Blur view Z position, it works on API 21 and above. For supporting lower API versions, you should add another Blur view before FrameLayout (cardHolder) view in layout file and instead of using View.setZ(float) method, make proper Blur view visible.
2. When an item is expanded and other items are blurred, scrolling of RecyclerView still works but it doesn't affect on the functionality of my answer. If you need to disable it, you should define a callback in your Adapter and call it in override fun onClick(v: View?) method to notify activity or fragment to disable/enable RecyclerView scrolling.

You can use the blurry library https://github.com/wasabeef/Blurry . Its the easiest way of making a blurred background.

With this library, you only had to use below piece of snippet

Blurry.with(context).radius(10).sampling(8).color(Color.argb(66, 255, 255, 0)).async().onto(rootView);

Hope this will fit perfect according to your requirement!!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM