I want to implement new gmail like toolbar without nested scroll view, which is scroll able, but when scroll down background should be visible.
It will look like this:
It's not a nested scrollview, Its recyclerView.
If you want such a search bar, you can make it using CardView and Edittext or use Material searchbar library. You can place it locked at that position by using frameLayout or CoordinatorLayout.
Here is a sample Screen I made!.
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="#dadada"
android:layout_height="match_parent">
<android.support.v7.widget.CardView
app:cardUseCompatPadding="true"
android:layout_margin="8dp"
app:cardCornerRadius="8dp"
android:layout_width="match_parent"
android:layout_height="64dp">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/imageView2"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginStart="8dp"
android:src="#drawable/ic_menu_black_24dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="#+id/editText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:background="#android:color/transparent"
android:hint="Search..."
android:minWidth="100dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="#+id/imageView2"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:src="#drawable/ic_search_black_24dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
</android.support.design.widget.CoordinatorLayout>
Here is the result.
You just need create custom one in your Activity layout like
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<android.support.design.widget.CoordinatorLayout
android:id="#+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.CardView
android:layout_margin="16dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"/>
</android.support.design.widget.AppBarLayout>
</android.support.v7.widget.CardView>
</android.support.design.widget.CoordinatorLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</android.support.constraint.ConstraintLayout>
And change style of your activity to "NoActionBar". For me it help.
For anyone who is trying to implement this with a RecyclerView , just use item view types with different layouts.
BaseAdapter that holds the main data:
public class BaseAdapter extends RecyclerView.Adapter<BaseAdapter.BaseViewHolder>
#Override
#NonNull
public BaseViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
// this is the main adapter so by default
// it should display the main content.
// Notice the layout being inflated here
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_song_list, null);
return createViewHolder(v);
}
// BaseViewHolder is the ViewHolder of this adapter
protected BaseViewHolder createViewHolder(View view) {
return new BaseViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull final BaseViewHolder holder, final int position) {
// Do something here
}
Now create an abstract adapter that extends the previous adapter:
public abstract class BaseHeaderAdapter extends BaseAdapter {
protected static final int ITEM_HEADER = 0;
protected static final int ITEM_LIST = 1;
#NonNull
#Override
public BaseAdapter.BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == ITEM_HEADER) {
// Notice the layout being inflated here
// This is a different layout
View view = LayoutInflater.from(activity).inflate(R.layout.item_tab_header, parent, false);
return createViewHolder(view);
}
// This will return the default layout from the extended adapter
return super.onCreateViewHolder(parent, viewType);
}
// BaseAdapter and BaseViewHolder are extended
#Override
protected BaseAdapter.BaseViewHolder createViewHolder(View view) {
// Notice: BaseHeaderAdapter is the current adapter
// BaseViewHolder is the extended holder
return new BaseHeaderAdapter.BaseViewHolder(view);
}
#Override
public int getItemCount() {
int superItemCount = super.getItemCount();
return superItemCount == 0 ? 0 : superItemCount + 1;
}
#Override
public int getItemViewType(int position) {
return position == 0 ? ITEM_HEADER : ITEM_LIST;
}
// This adapter's ViewHolder
public class BaseHeaderViewHolder extends BaseAdapter.BaseViewHolder {
...
}
}
Now the adapter that displays everything:
public class MyAdapter extends BaseHeaderAdapter
.....
#Override
protected BaseAdapter.BaseViewHolder createViewHolder(View view) {
return new MyAdapter.BaseViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull final BaseAdapter.BaseViewHolder holder, int position) {
if (holder.getItemViewType() == ITEM_HEADER) {
// do some stuff
holder.mHeaderTitle.setText("Header");
} else {
super.onBindViewHolder(holder, position - 1);
}
}
// The ViewHolder extends the BaseHeaderAdapter.BaseHeaderViewHolder
You can also solve this with an AppBarLayout and a custom CoordinatorLayout.Behavior. First, setup the layout in this way:
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior=".view.SearchBarBehaviour">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
.../>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/transparent"
app:elevation="0dp">
<!-- the searchbar with a layout_margin and transparent background etc -->
<include layout="#layout/searchbar" />
</com.google.android.material.appbar.AppBarLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Note the custom behavior set to the SwipeRefreshLayout. It looks like that:
class SearchBarBehaviour(
context: Context,
attrs: AttributeSet
) : CoordinatorLayout.Behavior<View>(context, attrs) {
private var previousY: Float = 0f
override fun layoutDependsOn(
parent: CoordinatorLayout,
child: View, dependency: View
): Boolean = dependency is AppBarLayout
override fun onDependentViewChanged(
parent: CoordinatorLayout,
child: View,
dependency: View
): Boolean {
val currentY = dependency.y
// When the AppBarLayout scrolls, scroll the RecyclerView for the same distance
(child as SwipeRefreshLayout)
.getChildAt(0)
.scrollBy(0, (previousY - currentY).toInt())
previousY = currentY
return false
}
}
This obviously also works without a SwipeRefreshLayout if you attach the behavior directly to a RecyclerView/NestedScrollView/... and adjust the line in the custom behaviour to scroll the child itself.
This solves the RecyclerView resizing issue of the default ScrollingViewBehavior which causes the RecyclerView to pop up its items when scrolling down.
Related
I am working with Nested recyclerView, which mean a RecylerView's item also has a RecyclerView in it. I know basic approach using RecyclerView.Adapter but I want to achieve this using ListAdapter. Is it even possible to get this with ListAdapter?
My activity_main.xml looks like this
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView
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">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:fitsSystemWindows="true">
<include
android:id="#+id/title_layout"
layout="#layout/item_title_profile"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/parent_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:paddingTop="10dp"
android:paddingBottom="60dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="#+id/title_layout" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
And this is my item_row_parent.xml.
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView 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"
android:layout_margin="15dp"
app:cardCornerRadius="10dp"
app:cardElevation="1dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/content_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:includeFontPadding="false"
android:padding="10dp"
android:text="House of Stark"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/child_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/content_title" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
How to get it done using ListAdapter?
So I would say that the easiest/fastest and most reliable option would be to create a new RecyclerView.Adapter.
But if you can't do that you can try to wrap ListAdapter into RecycerView.Adapter, and proxy/pass all of the requests directly to ListAdapter.
This is sample usage to show the idea, to properly handle dataset changes you will need to add some additional data observers etc.
public class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {
private ListAdapter mListAdapter;
public MyAdapter(ListAdapter listAdapter) {
mListAdapter = listAdapter;
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
// Inflate the view for a single item in the RecyclerView.
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout, parent, false);
return new MyViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull MyViewHolder holder, int position) {
// Get the item from the ListAdapter at the specified position.
Object item = mListAdapter.getItem(position);
// Bind the item data to the view holder.
mListAdapter.getView(position, holder.itemView, parent);
}
#Override
public int getItemCount() {
return mListAdapter.getCount();
}
static class MyViewHolder extends RecyclerView.ViewHolder {
public MyViewHolder(#NonNull View itemView) {
super(itemView);
}
}
}
I have a layout with a view pager and consist of 2 fragments with recycler view
The first four-row is clickable, but the other is not clickable, it's happen in tablet mode.
In Phone mode, everything is working fine.
The strange thing is if the data is short(1 letter only), everything is clickable, but the data is long(more than 3 letters) then it's not clickable from row 4. The FAB button is working. I have already tried using physical tablet and emulated tablet.
I am using View Pager 2
Is this a bug? And how to solve this?
Edited, My RecyclerView Adapter code
private List<Craft> craftList;
private RecyclerViewClickListener clickListener;
private Context mContext;
public int selectedItem = -1;
public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public TextView name ;
public View container;
private RecyclerViewClickListener mListener;
public MyViewHolder(View view, RecyclerViewClickListener listener) {
super(view);
mListener = listener;
name = (TextView) view.findViewById(R.id.name);
container = view.findViewById(R.id.container);
container.setOnClickListener(this);
}
#Override
public void onClick(View v) {
selectedItem = getBindingAdapterPosition();
if(selectedItem!= RecyclerView.NO_POSITION){
mListener.OnButtonClick(v, getBindingAdapterPosition());
notifyDataSetChanged();
}
}
}
public interface RecyclerViewClickListener {
void OnButtonClick(View view, int position);
}
public CraftAdapter(List<Craft> craftList, RecyclerViewClickListener listener) {
this.craftList = craftList;
clickListener = listener;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.craft_item, parent, false);
mContext = parent.getContext();
return new MyViewHolder(itemView,clickListener);
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
Craft craft = craftList.get(position);
holder.name.setText(craft.getName());
if(mContext.getResources().getBoolean(R.bool.is_tablet)){
if(selectedItem == position){
holder.container.setBackgroundResource(R.color.light_blue);
}
else{
holder.container.setBackgroundResource(R.color.white);
}
}
}
#Override
public int getItemCount() {
return craftList.size();
}
After wasting so much time. I finally found the root cause.
The cause is the layout using LinearLayout with weight. The weight make it not working, I think it's a bug. But I can solve it using constraintlayout
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.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:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white"
android:id="#+id/coordinator_layout">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment android:name="CraftFragment"
android:id="#+id/list_fragment"
android:layout_weight="2" -->>This is the root cause
android:layout_width="0dp" -->> This is the root cause
android:layout_height="match_parent"
/>
<View
android:layout_width="1dp"
android:layout_height="match_parent"
android:background="#color/dark_grey2"/>
<FrameLayout
android:id="#+id/detail_fragment"
android:layout_weight="3"
android:layout_width="0dp"
android:layout_height="match_parent" />
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
So I change it to:
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.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:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white"
android:id="#+id/coordinator_layout">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment android:name="CraftFragment"
android:id="#+id/list_fragment"
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="match_parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="#+id/detail_fragment"
app:layout_constraintHorizontal_weight="2"/>
<FrameLayout
android:id="#+id/detail_fragment"
android:layout_weight="3"
android:layout_width="0dp"
android:layout_height="match_parent"
app:layout_constraintLeft_toRightOf="#+id/list_fragment"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintHorizontal_weight="3"/>
<View
android:id="#+id/divider"
android:layout_width="1dp"
android:layout_height="match_parent"
android:background="#color/dark_grey2"
app:layout_constraintLeft_toRightOf="#id/list_fragment"
app:layout_constraintRight_toRightOf="#id/list_fragment"/>
</androidx.constraintlayout.widget.ConstraintLayout>
I have a very simple scenario involving a NestedScrollView and LinearLayout where I want the LinearLayout to translate as the NestedScrollView scrolls up. Here is the layout in picture:(the concerned child view is the second last LinearLayout with the Id of linearlayout )
<?xml version="1.0" encoding="utf-8"?>
<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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.snapsboardmainpage.MainActivity"
tools:layout_editor_absoluteX="8dp"
tools:layout_editor_absoluteY="8dp">
<android.support.v4.widget.NestedScrollView
android:id="#+id/nested_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="#+id/linearLayout3"
android:layout_width="match_parent"
android:layout_height="40dp"
android:orientation="vertical"
android:layout_gravity="top"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="0dp"
android:layout_marginRight="0dp"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginLeft="0dp"
app:layout_constraintLeft_toLeftOf="parent">
</LinearLayout>
<LinearLayout
android:id="#+id/linearLayout1"
android:layout_width="0dp"
android:layout_height="112dp"
android:orientation="vertical"
android:background="#android:color/holo_green_light"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#id/linearLayout3">
</LinearLayout>
<android.support.v4.view.ViewPager
android:id="#+id/id_viewpager_photosvideos_albums"
android:layout_width="0dp"
android:layout_height="1000dp"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#+id/linearLayout1">
<android.support.design.widget.TabLayout
android:id="#+id/id_tab_photosvideos_albums"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top">
<android.support.design.widget.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<android.support.design.widget.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</android.support.design.widget.TabLayout>
</android.support.v4.view.ViewPager>
</android.support.constraint.ConstraintLayout>
</android.support.v4.widget.NestedScrollView>
<LinearLayout
android:id="#+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="40dp"
android:orientation="vertical"
android:layout_gravity="top"
app:layout_behavior="com.example.snaps.TopActionBarBehavior"
android:background="#android:color/holo_blue_light">
</LinearLayout>
<LinearLayout
android:id="#+id/linearLayout2"
android:layout_width="match_parent"
android:layout_height="56dp"
android:orientation="vertical"
android:layout_gravity="bottom"
android:background="#android:color/holo_orange_light">
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
And, the concerned behavior(TopActionBarBehavior) as follows:
public class TopActionBarBehavior extends CoordinatorLayout.Behavior<LinearLayout> {
private static final String TAG = "TopActionBarBehavior";
private int thresholdScrollDistance;
private int mNestedScrollViewInitialTop;
public TopActionBarBehavior() {
}
public TopActionBarBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean layoutDependsOn(CoordinatorLayout parent, LinearLayout child, View dependency) {
return dependency instanceof NestedScrollView;
}
#Override
public boolean onDependentViewChanged(CoordinatorLayout parent, LinearLayout child, View dependency) {
// Translate the child view as per the NestedScrollView
int currentNestedScrollViewTop = dependency.getTop();
// Have we scrolled up?
if(currentNestedScrollViewTop > mNestedScrollViewInitialTop){
// Translate the child view by the same distance
child.setTranslationY(currentNestedScrollViewTop - mNestedScrollViewInitialTop);
}
return true;
}
#Override
public boolean onLayoutChild(CoordinatorLayout parent, LinearLayout child, int layoutDirection) {
View topBar = parent.findViewById(R.id.linearLayout);
int topBarHeight = topBar.getHeight();
View nestedScrollView = parent.findViewById(R.id.nested_container);
mNestedScrollViewInitialTop = nestedScrollView.getTop();
View profileBar = parent.findViewById(R.id.linearLayout1);
int profileBarHeight = profileBar.getHeight();
View dummyTopBarUnderlay = parent.findViewById(R.id.linearLayout3);
int dummyTopBarHeight = dummyTopBarUnderlay.getHeight();
View tabLayout = parent.findViewById(R.id.id_tab_photosvideos_albums);
int tabLayoutHeight = tabLayout.getHeight();
thresholdScrollDistance = profileBarHeight + dummyTopBarHeight + tabLayoutHeight;
return super.onLayoutChild(parent, child, layoutDirection);
}
}
I tried debugging and layoutDependsOn() is getting called as it should be but onDependentViewChanged() is getting called only once.
Finally found the answer after countless hours of debugging. My NestedScrollView wasn't actually moving at all; it's content was moving the whole time which didn't trigger this method. For scroll events, we can tap onto the onNested*() methods in the Behavior class. Simple.
i'm having problem with Videoview. i have done all the settings right but still it dosen't show anything in Videoview. finally i used a library but the problem was'nt solved. i used the videoview inside the recyclerview like the example in github: (https://github.com/Krupen/AutoplayVideos), here is my code, and single_view is the layout for each item:
single_view:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:bvp="http://schemas.android.com/tools"
android:id="#+id/lay_parent_parentView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="#dimen/parent_margin"
android:layout_marginLeft="#dimen/text_TD_padding_listItem"
android:layout_marginRight="#dimen/text_TD_padding_listItem"
android:layout_marginTop="#dimen/parent_margin"
android:backgroundTint="#color/white"
card_view:cardBackgroundColor="#color/white"
card_view:cardCornerRadius="5dp"
card_view:cardElevation="5dp">
<!--style="#style/CardViewStyle"-->
<FrameLayout
android:layout_width="300dp"
android:layout_height="150dp">
<com.allattentionhere.autoplayvideos.AAH_VideoImage
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="hello"/>
this is my main layout which contains the recyclerview:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/parent_storyDet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:fitsSystemWindows="false"
android:layoutDirection="rtl"
android:orientation="vertical"
>
<android.support.v4.widget.NestedScrollView
android:id="#+id/scrollView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layoutDirection="rtl"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context="com.homaplus.hashtag.hashtag.Fragments.Frag_story_detail">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.allattentionhere.autoplayvideos.AAH_CustomRecyclerView
android:id="#+id/recycler_storyRelatedVideos"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_alignParentTop="true"
android:nestedScrollingEnabled="false" />
</RelativeLayout>
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
The recyclerView Adapter:
public class MyVideosAdapter extends AAH_VideosAdapter {
private List<String> list;
public class MyViewHolder extends AAH_CustomViewHolder {
//to mute/un-mute video (optional)
boolean isMuted;
public MyViewHolder(View x) {
super(x);
}
}
public MyVideosAdapter(List<String> list_urls) {
this.list = list_urls;
}
#Override
public AAH_CustomViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.row_videos, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(AAH_CustomViewHolder holder, int position) {
holder.setVideoUrl(list.get(position));
}
#Override
public int getItemCount() {
return list.size();
}
#Override
public int getItemViewType(int position) {
return 0;
}
}
finally i set the recyclerview in my fragment as folloe:
LinearLayoutManager linearLayoutManager2 = new LinearLayoutManager(getContext());
linearLayoutManager2.setOrientation(LinearLayoutManager.HORIZONTAL);
recycler_storyRelatedVideos.setActivity(getActivity());
recycler_storyRelatedVideos.setLayoutManager(linearLayoutManager2);
adapter_videos = new MyVideosAdapter(story.getList_storyVideos());
recycler_storyRelatedVideos.setHasFixedSize(true);
recycler_storyRelatedVideos.setAdapter(adapter_videos);
recycler_storyRelatedVideos.smoothScrollBy(0,1);
recycler_storyRelatedVideos.smoothScrollBy(0,-1);
I'm trying to animate animate the transition from a recyclerview item to an activity with details about that item. I've followed this example:
https://developer.android.com/training/material/animations.html#Transitions
The activities both use shared view elements. The transitions are working, but not as smooth as I would expect. What I mean by that is during the transition, the text shortly falls outside the cardview and the image snaps back in place. See the video:
Video exmaple
NOTE: I do use android databinding and a viewpagaer. I'm not sure if this matters or not for my issue.
In multiple awnsers I've seen people use:
android:clipChildren="false"
android:clipToPadding="false"
But even if I put that on all parents, it still happens. What am i doing wrong?
List Fragment:
#Override
public void onViewCreated(final View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
//Adapter & recyclerview init
mAdapter = new ProductListAdapter(productList, new OnProductClickListener() {
#Override
public void onProductClick(View view1, Product product) {
final View viewProductCv = view1.findViewById(R.id.list_product_cv);
Intent intent = new Intent(getActivity(), ProductDetailPage.class);
intent.putExtra(PRODUCT, product);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(getActivity(),
Pair.create(viewProductCv, "productCardView")); // similar name
startActivity(intent, options.toBundle());
} else
startActivity(intent);
}
});
}
Recyclerview item layout
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="product"
type="com.icemobile.estimotemirror.model.Product" />
</data>
<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="#+id/list_product_cv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:transitionName="productCardView" <!-- similar name -->
android:layout_margin="#dimen/card_margin"
card_view:cardCornerRadius="#dimen/card_corner_radius">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="#+id/list_product_image"
android:layout_width="match_parent"
android:layout_height="150dp"
android:scaleType="fitCenter"
android:src="#{product.image}"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:orientation="vertical"
android:padding="8dp">
<TextView
android:id="#+id/list_product_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#{product.name}"
android:textColor="#color/colorPrimary"
android:textSize="#dimen/title_14" />
<TextView
android:id="#+id/list_product_distance"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#{product.distance}"
android:textSize="#dimen/text_12" />
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
</layout>
Activity details layout
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:card_view="http://schemas.android.com/tools">
<data>
<variable
name="product"
type="com.icemobile.estimotemirror.model.Product" />
</data>
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:background="?attr/colorPrimary"
android:elevation="6dp"
android:minHeight="?attr/actionBarSize"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.CardView
android:id="#+id/details_card_view"
android:layout_width="250dp"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:transitionName="productCardView" <!-- similar name -->
android:layout_gravity="center"
android:layout_marginLeft="#dimen/card_margin"
android:layout_marginRight="#dimen/card_margin"
android:layout_marginTop="86dp"
card_view:cardCornerRadius="#dimen/card_corner_radius">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="#dimen/activity_horizontal_margin">
<ImageView
android:id="#+id/list_product_image"
android:layout_width="match_parent"
android:layout_height="200dp"
android:scaleType="fitCenter"
android:src="#{product.image, default=#drawable/default_thumbnail}"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="75dp"
android:gravity="center"
android:orientation="vertical"
android:padding="8dp">
<TextView
android:id="#+id/detail_product_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#{product.name}"
android:textColor="#color/colorPrimary"
android:textSize="#dimen/title_18" />
<TextView
android:id="#+id/detail_product_distance"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#{product.distance}"
android:textSize="#dimen/text_14" />
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
<TextView
android:id="#+id/detail_product_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentStart="true"
android:layout_below="#+id/details_card_view"
android:layout_marginTop="#dimen/activity_vertical_margin"
android:gravity="center"
android:padding="#dimen/activity_horizontal_margin"
android:text="dedscription"
android:textColor="#color/colorPrimary"
android:textSize="#dimen/title_14" />
</RelativeLayout>
</ScrollView>
</android.support.design.widget.CoordinatorLayout>
</layout>
My recyclerview Adapter:
public class ProductListAdapter extends RecyclerView.Adapter<ProductListAdapter.ViewHolder> {
private List<Product> productList;
private final OnProductClickListener listener;
public ProductListAdapter(List<Product> productList, OnProductClickListener listener) {
this.productList = productList;
this.listener = listener;
}
#Override
public ProductListAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
ViewDataBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item_product, parent, false);
return new ViewHolder(binding);
}
#Override
public void onBindViewHolder(final ProductListAdapter.ViewHolder viewHolder, final int position) {
Product product = productList.get(position);
viewHolder.bind(product, listener);
}
#Override
public int getItemCount() {
return (productList != null) ? productList.size() : 0;
}
public void clear() {
this.productList.clear();
}
public void add(Product product) {
this.productList.add(product);
}
class ViewHolder extends RecyclerView.ViewHolder {
private final ViewDataBinding binding;
private ViewHolder(ViewDataBinding binding) {
super(binding.getRoot());
this.binding = binding;
}
void bind(final Product product, final OnProductClickListener listener) {
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
listener.onProductClick(v, product);
}
});
binding.setVariable(BR.product, product);
binding.executePendingBindings();
}
}
Any help would be appreciated!
This is a common issue with data binding and recyclerviews. The Data does not bind on the same frame as the viewholder, it waits a little bit. You need to make sure to add the following method when you use databinding in the recyclerview.adapter or viewholder so it binds immediately.
public void bind(Product product){
mBinding.getViewModel().setProduct(product);
mBinding.executePendingBindings();
}
In my case the childeren of the cardview that was used for shared element transition had a slightly different xml layout in the 2nd activity, that probably caused the stutter. Now I've kept the layout the same and the transition is smooth.