BUG Some row in recyclerview not clickable inside view pager in tablet - android

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>

Related

How I implement new material gmail toolbar without nested scrollview?

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.

How to save scroll position of recyclerview in fragment

I have followed so many answers from here.. but not a single one solving my issue .. that's why i am asking.
I want to save scroll position in a fragment.
In So many articles they have suggested to follow
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
and
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
}
But this two method is not available in fragment.
My code:
private int mPositionIng = RecyclerView.NO_POSITION;
private String KEY_POSITION_ING = "KeyPositionIng";
in OnCreateView()
if (savedInstanceState != null) {
if (savedInstanceState.containsKey(KEY_POSITION_ING)) {
mPositionIng = savedInstanceState.getInt(KEY_POSITION_ING);
}
}
Override Methods in fragment They are not same method as above. i don't know where i am doing wrong.
#Override
public void onSaveInstanceState(Bundle outState) {
int scrollPositionIng = mRecyclerViewIngredients.computeVerticalScrollOffset();
mPositionIng = scrollPositionIng;
outState.putInt(KEY_POSITION_ING, mPositionIng);
super.onSaveInstanceState(outState);
}
#Override
public void onViewStateRestored(#Nullable Bundle savedInstanceState) {
if (mPositionIng != RecyclerView.NO_POSITION) {
mRecyclerViewIngredients.getLayoutManager().scrollToPosition(mPositionIng);
}
super.onViewStateRestored(savedInstanceState);
}
I just need to save scroll position while the orientation changes .. Please help.
Any Suggestion will be help full. Thanks......
Update
Everything I wrote below is correct, but the reason it didn't work for you is that I didn't realize how your Activity's layout was structured. Here is your Activity's layout (slightly cleaned up):
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.tapan.recipemaster.activity.RecipeDetailActivity">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<FrameLayout
android:id="#+id/fl_fragment_detail"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="#dimen/padding_10dp"/>
</RelativeLayout>
</ScrollView>
</android.support.constraint.ConstraintLayout>
Meanwhile, this is your Fragment's layout (again, slightly cleaned up):
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.tapan.recipemaster.fragment.RecipeDetailFragment">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="#dimen/padding_10dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/colorAccent"
android:orientation="vertical">
<TextView
android:id="#+id/tv_ingredient"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#FFF"
android:textSize="#dimen/text_23sp"
android:text="Ingredients"/>
<android.support.v7.widget.RecyclerView
android:id="#+id/rv_ingredients"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/dimen_8dp"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="#+id/tv_step"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/dimen_8dp"
android:textColor="#color/colorPrimaryDark"
android:textSize="#dimen/text_23sp"
android:text="Steps"/>
<android.support.v7.widget.RecyclerView
android:id="#+id/rv_steps"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/dimen_8dp"/>
</LinearLayout>
</LinearLayout>
</ScrollView>
</FrameLayout>
Both RecyclerViews have android:layout_height="wrap_content", which means they do not scroll. Rather, the ScrollView in your Activity is the view providing the scrolling behavior, so it is this view whose scroll position must be saved.
You can have the system do this for you by giving this ScrollView an id. Any id you want, as long as it's unique. You don't have to write any Java at all.
<ScrollView
android:id="#+id/thisfixestheproblem"
android:layout_width="match_parent"
android:layout_height="match_parent">
Make sure you're modifying the ScrollView in your activity's layout, not the one in your fragment's layout.
Original
None of the code you posted should be necessary to save your RecyclerView's scroll position on orientation change. As long as the RecyclerView has a unique ID in your layout, it will save the scroll position for you automatically.
Here is a very small sample app that shows automatic saving of scroll position, even with a dynamically added Fragment. As you can see, the only instance state I'm saving myself is whether the button to start the fragment should be visible.
MainActivity.java
public class MainActivity extends AppCompatActivity {
private Button button;
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean("buttonVisible", button.getVisibility() == View.VISIBLE);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.content, new MyFragment())
.commit();
button.setVisibility(View.GONE);
}
});
if (savedInstanceState != null) {
boolean buttonVisible = savedInstanceState.getBoolean("buttonVisible");
button.setVisibility(buttonVisible ? View.VISIBLE : View.GONE);
}
}
}
MyFragment.java
public class MyFragment extends Fragment {
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.myfragment, container, false);
RecyclerView recycler = (RecyclerView) root.findViewById(R.id.recycler);
recycler.setAdapter(new MyAdapter());
return root;
}
private static class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View itemView = inflater.inflate(R.layout.itemview, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
Drawable d = new ColorDrawable(Color.argb(0xff, 0, 0, position));
ViewCompat.setBackground(holder.image, d);
holder.text.setText("" + position);
}
#Override
public int getItemCount() {
return 256;
}
}
private static class MyViewHolder extends RecyclerView.ViewHolder {
final View image;
final TextView text;
MyViewHolder(View itemView) {
super(itemView);
this.image = itemView.findViewById(R.id.image);
this.text = (TextView) itemView.findViewById(R.id.text);
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="create fragment"/>
</FrameLayout>
myfragment.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView
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/recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutManager="android.support.v7.widget.LinearLayoutManager"
tools:listitem="#layout/itemview"/>
itemview.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<View
android:id="#+id/image"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_margin="12dp"
tools:background="#333"/>
<TextView
android:id="#+id/text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
tools:text="text"/>
</LinearLayout>
Let the Android OS handle that for you, in AndroidManifest.xml inside your wanted tag activity add:
android:configChanges="orientation|screenSize"
for future coders
I guess when you came back to your fragment you lost position this is because the values stored in the recycler view of the fragment is lost. If you keep code in start or other methods in fragment their scope is lost.
keep your code in On Create View in fragment because scope will not be lost it will work maximum times if not try by declaring all variables in class not in local method and initialize in oncreateview method. how to get context in on create view?? you can google

videoview in android application is totaly blank

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

Horizontal RecyclerView with items that have dynamic height

So I need a horizontal RecyclerView. However, the items in them have dynamic heights based on what's returned from the backend.
The RecyclerView and its items have the height of "wrap_content"
The problem is if the first visible items in the RecyclerView are small, then when the user scrolls to the larger items, they appear cut off.
Ideally, we want the RecyclerView to be large enough to hold the largest item in the group (but only the largest existing item... not the hypothetically largest item). The RecyclerView dynamically changing its height is also acceptable.
I wrote an example app to illustrate the problem. In this app, we have a horizontal list. The first 33 items should show 1 line of text, while the next should show 3 lines of text, and the last 34 should show 2 lines. However, they all show 1 line, because the height of the RecyclerView doesn't change.
I've tried calling requestLayout() on the RecyclerView (and on the TextView) from onBindViewHolder(), but it doesn't seem to do anything.
MainActivity:
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private RecyclerView.Adapter mAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAdapter = createAdapter();
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
mRecyclerView.setAdapter(mAdapter);
}
private RecyclerView.Adapter<ViewHolder> createAdapter() {
RecyclerView.Adapter adapter = new RecyclerView.Adapter<ViewHolder>() {
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
return new ViewHolder(v);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
if (position < 33) {
holder.mText.setText("1 line");
} else if (position > 66) {
holder.mText.setText("2 lines\n2 lines");
} else {
holder.mText.setText("3 lines\n3 lines\n3 lines");
}
}
#Override
public int getItemCount() {
return 100;
}
};
return adapter;
}
private static class ViewHolder extends RecyclerView.ViewHolder {
TextView mText;
public ViewHolder(View itemView) {
super(itemView);
mText = (TextView) itemView.findViewById(R.id.text);
}
}
}
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin">
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#888888">
<TextView
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hi"
android:textSize="30sp" />
</LinearLayout>
Change your recyclerView height & width from wrap_content to match_parent or you can also give fixed height to your recyclerView like android:layout_height="150dp"
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#888888" />
</RelativeLayout>
or You can try
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="150dp"
android:background="#888888" />
</RelativeLayout>
Change your item.xml layout content with the below code.
It will solve your issue.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="160dp"
android:layout_height="match_parent"
android:background="#888888">
<TextView
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hi"
android:textSize="30sp" />
</LinearLayout>
You can solve this issue using the FlexboxLayoutManager Google library by defining the FlexDirection to FlexDirection.ROW and FlexWrap to FlexWrap.NOWRAP and also in your BaseViewHolder constructor set for each item the FlexShrink to 0.0f to be able to scroll horizontally. More details of how to achieve this can be found here: Horizontal RecyclerView with dynamic item’s Height
MainActivity:
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private RecyclerView.Adapter mAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAdapter = createAdapter();
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
mRecyclerView.setAdapter(mAdapter);
}
private RecyclerView.Adapter<ViewHolder> createAdapter() {
RecyclerView.Adapter adapter = new RecyclerView.Adapter<ViewHolder>() {
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
return new ViewHolder(v);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
if (position < 33) {
holder.mText.setText("1 line");
} else if (position > 66) {
holder.mText.setText("2 lines\n2 lines");
} else {
holder.mText.setText("3 lines\n3 lines\n3 lines");
}
}
#Override
public int getItemCount() {
return 100;
}
};
return adapter;
}
private static class ViewHolder extends RecyclerView.ViewHolder {
TextView mText;
public ViewHolder(View itemView) {
super(itemView);
mText = (TextView) itemView.findViewById(R.id.text);
}
}
}
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin">
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#888888">
<TextView
android:id="#+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Hi"
android:textSize="30sp" />
</LinearLayout>
To make RecyclerView Horizontal you need to use android:layout_centerHorizontal="true". Also, everything more are the same as vertical.
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/RecyclerView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_below="#id/toolbar"/>
Try to add your textView android:singleLine="false" it changes when there are multiple lines
Just call itemAdapter.notifyDataSetChanged();

CardView - mysterious gaps emerge when scrolling upwards

I finally managed to get the card view to look just like I want it.
I use a GridLayoutManager with two columns to display cards with a thumbnail. Everything nice and working so far.
Anyway, once I scroll up, everything blows up. Large gaps (the size of a card itself) emerge between each row, now I every second row will be an empty one. I do not understand how that would possibly happen. I don't have any problem while scrolling down, but even one inch back up and everything is in pieces (so to speak).
Maybe some can see what is wrong with the layout.
actvivity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical">
<android.support.v7.widget.Toolbar xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/my_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:elevation="4dp"
android:theme="#style/ThemeOverlay.AppCompat.ActionBar"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
app:titleTextColor="#android:color/primary_text_dark" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="16dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="16dp"
tools:context=".view.MainActivity">
<android.support.v7.widget.RecyclerView
android:id="#+id/series_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentStart="true"
android:scrollbars="vertical"
/>
</RelativeLayout>
card.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/layout_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.CardView
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/card_view"
android:layout_width="160dp"
android:layout_height="270dp"
android:layout_gravity="center"
android:layout_margin="5dp"
android:elevation="3dp"
app:cardUseCompatPadding="true"
app:cardCornerRadius="0dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/thumbnail"
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="true"
/>
<TextView
android:id="#+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/thumbnail"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="10dp"
android:textColor="#color/colorSeriesTitle"
android:textSize="15dp" />
<TextView
android:id="#+id/rating"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/title"
android:paddingBottom="5dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:textSize="12dp" />
</RelativeLayout>
</android.support.v7.widget.CardView>
Adapter
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder>{
private List<Stuff> stuff;
private Callback callback;
private Context context;
public MyAdapter(Context context) {
this.context = context;
stuff = Collections.emptyList();
}
public MyAdapter(List<Stuff> stuff) {
this.stuff = stuff;
}
public void setStuff(List<Stuff> stuff) {
this.stuff = stuff;
}
public void setCallback(Callback callback) {
this.callback = callback;
}
public static class MyViewHolder extends RecyclerView.ViewHolder {
public Stuff stuff;
public View contentLayout;
public ImageView thumbnailImageView;
public TextView titleTextView;
public TextView ratingTextView;
public MyViewHolder(View itemView) {
super(itemView);
contentLayout = itemView.findViewById(R.id.layout_content);
thumbnailImageView = (ImageView) itemView.findViewById(R.id.thumbnail);
titleTextView = (TextView) itemView.findViewById(R.id.title);
ratingTextView = (TextView) itemView.findViewById(R.id.rating);
}
}
public interface Callback {
void onItemClick(Series series);
}
#Override
public SeriesViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.series_card, parent, false);
final MyViewHolderviewHolder = new MyViewHolder(itemView);
viewHolder.contentLayout.setOnClickListener(view -> {
if (callback != null) {
callback.onItemClick(viewHolder.series);
}
});
return viewHolder;
}
#Override
public void onBindViewHolder(MyViewHolderholder, int position) {
Stuff stuff = this.stuff.get(position);
holder.stuff = stuff;
holder.titleTextView.setText(stuff.getName())
holder.ratingTextView.setText(stuff.getStatus());
Picasso.with(context)
.load(stuff.getSomeImageURL())
.fit()
.centerCrop()
.into(holder.thumbnailImageView);
}
#Override
public int getItemCount() {
return stuff.size();
}
card.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/layout_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
Changing the layout_height to wrap_content fixed the problem.

Categories

Resources