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);
}
}
}
}
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.