RecyclerView contents in NestedScrollView disappears after been scrolled out of view - android

I have a Recyclerview in a Nestedscrollview.It shows very well on loading showing all the contents of my customadapter but on scrolling some items away from sight and scrolling it back to them,the textviews will be gone.But imageviews doesnt behave like this.I have the Recyclerview in my Activity onCreate implemented this way
styles=response.body();
adapter=new DesignerStylesAdapter(styles);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(DesignerActivity.this,RecyclerView.HORIZONTAL,false);
mLayoutManager.setAutoMeasureEnabled(true);
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setNestedScrollingEnabled(false);
recyclerView.setAdapter(adapter);
and in activity layout file
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:behavior_overlapTop="52dp"
android:fillViewport="true"
android:id="#+id/nestedscrollview"
app:layout_behavior="#string/appbar_scrolling_view_behavior" >
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:scrollbars="vertical"
android:layout_below="#+id/line"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</android.support.v4.widget.NestedScrollView>
and in my custom adapter's onBindViewHolder,Im not calling setVisibility on any view
#Override
public void onBindViewHolder(final ViewHolder holder,final int position){
final Context context = holder.productPic.getContext();
final CustomStyles style=styles.get(position);
holder.productName.setText(style.getName());
holder.productPrice.setText("₦"+ NumberFormat.getNumberInstance(Locale.US).format(style.getCustomPrice()));
Picasso.with(context)
.load(style.getPhoto1())
.into(holder.productPic);
}
Someone kindly help out,Ive been stuck on this issue for the whole day.

Related

Scroll to Particular Position in (Vertical & Horizontal Scroll Enabled) Grid Layout - RecyclerView - Android

I have Implemented a RecyclerView with GridLayoutManager which has both Vertical and Horizontal Scroll , I need to scroll the layout to particular position , referred many codes but it did'nt worked out for me .
Java Class code :
void RackGen()
{
STRarray = (String[]) mStringList.toArray(new String[mStringList.size()]);
ROWarray = (String[]) mRowList.toArray(new String[mRowList.size()]);
numcol = Integer.parseInt(col);
numdata = Integer.parseInt(num);
rv = (RecyclerView) findViewById(R.id.rview);
int numberOfColumns = numcol;
GridLayoutManager GM2 = new GridLayoutManager(this,numberOfColumns);
rv.setLayoutManager(GM2);
rv.setNestedScrollingEnabled(true);
rv.setHasFixedSize(true);
adapter = new MyRecyclerViewAdapter(this, STRarray, ROWarray);
rv.setAdapter(adapter);
XML :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="20dp"
android:layout_centerHorizontal="true"
android:id="#+id/llzoom"
android:orientation="vertical"
>
<android.support.v4.widget.NestedScrollView
android:id="#+id/nested_scroll_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:android="http://schemas.android.com/apk/res/android">
<HorizontalScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scrollbars="none"
android:overScrollMode="never">
<android.support.v7.widget.RecyclerView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/rview">
</android.support.v7.widget.RecyclerView>
</HorizontalScrollView>
</ScrollView>
</android.support.v4.widget.NestedScrollView>
</LinearLayout>
Only after adding nested scroll view along with vertical and horizontal scroll , scrolling worked smoothly on both directions . Now i need to scroll to particular position.
Thank You
You need to reference to your NestedScrollView inside your activity and then call the scrollTo(x,y) on that object, example:
NestedScrollView nestedScrollView = (NestedScrollView) findViewById(R.id.nested_scroll_view);
nestedScrollView.scrollTo(x,y);
x and y are horizontal and vertical scrolls.
I know this is an older post, and I haven't tested this code on nested scroll views, but as you only have one position value, you can try this technique.
This works great for scrolling to the currently selected view of a recyclerview GridLayoutManager with dynamic autofit (I use a custom recyclerview for autofit, not the grid itself).
After I set the adapter:
recyclerView.setAdapter(adapter);
I put (just under it in onCreate):
recyclerView.post(new Runnable()
{
#Override
public void run()
{
layoutManager.scrollToPositionWithOffset(currentSelected, 0);
}
});
It waits for the views to be drawn, then it scrolls to the position given. It works wonderfully!
I got the idea here: https://stackoverflow.com/a/52895262/2905354

CoordinatorLayout/AppBarLayout interfere with RecyclerView scrollToPosition(bottom scrolling)

This question has been asked many times but it just doesn't seem to have a solution that fits my requirement.
I have a Recipe that has instructions. Each instruction is ordered in a RecyclerView. The order must be from top to bottom. It cannot be reversed like many answers to this question.
I have an Add button that when clicked a new item is added at the bottom of the list. I need to scroll to the new item after the insert. So I employed the following code in the button's onClick event:
mRecyclerAdapter.addItem(newInstruction);
mRecyclerView.smoothScrollToPosition(mRecyclerAdapter.getItemCount() - 1);
This scrolls to the second last item because in the adapter's addItem() method I have this:
mItems.add(item);
notifyItemInserted(getItemCount() - 1);
I don't know the details of the notifyItemInserted() call, but it appears to be on a separate thread, which means that smoothScrollToPosition() is called before the views have been laid out after the insertion. Hence, it only scrolls to the second last item.
I have tried looking for a "callback" function along the lines of onItemInserted but I did not have any luck. eg, no answer Here.
How do I solve this problem?
EDIT START
I've simplified the code in a new project in hope to find the problem, and found out what the problem is. It appears to be a problem caused by CoordinatorLayout/AppBarLayout when scrolling flag is enabled. It seems as though the scrolling did not take into consideration the extra scrolling space added by the AppBarLayout.
In the sample codes below, if you disable the scrolling flag for the app bar, scrolling to the bottom of the screen works perfectly as intended. However, if you enable the AppBarLayout scrolling behavior, and change its height, you'll notice that scrolling to the bottom is off by the given height.
I need the scrolling behavior, so how do I make them play nicely with each other? Please note that I've changed the question to reflect the problem.
MainActivity.java
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
public static final int ITEMS_COUNT = 50;
private FloatingActionButton mFloatingActionButton;
private RecyclerView mRecyclerView;
private RecyclerAdapter mRecyclerAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mFloatingActionButton = (FloatingActionButton) findViewById(R.id.fabButton);
mFloatingActionButton.setOnClickListener(this);
setupRecyclerView();
}
private void setupRecyclerView() {
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerAdapter = new RecyclerAdapter(createItemList());
mRecyclerView.setAdapter(mRecyclerAdapter);
}
private List<String> createItemList() {
List<String> itemList = new ArrayList<>();
for (int i = 0; i < ITEMS_COUNT; i++) {
itemList.add("Item " + i);
}
return itemList;
}
#Override
public void onClick(View v) {
mRecyclerView.scrollToPosition(49);
}
}
activity_main.xml
<?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"
android:id="#+id/coordinatorLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="#+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- changing the height affects the scrolling distance -->
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="Header"
app:layout_scrollFlags="scroll|enterAlways"/> <!-- this is the problem -->
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
<android.support.design.widget.FloatingActionButton
android:id="#+id/fabButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:layout_margin="20dp"/>
</android.support.design.widget.CoordinatorLayout>
RecyclerAdapter.java
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<String> mItemList;
public RecyclerAdapter(List<String> itemList) {
mItemList = itemList;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
View view = LayoutInflater.from(context).inflate(R.layout.recycler_item, parent, false);
return RecyclerItemViewHolder.newInstance(view);
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
RecyclerItemViewHolder holder = (RecyclerItemViewHolder) viewHolder;
String itemText = mItemList.get(position);
holder.setItemText(itemText);
}
#Override
public int getItemCount() {
return mItemList == null ? 0 : mItemList.size();
}
}
recycler_item.xml
<?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"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="8dp"
card_view:cardCornerRadius="4dp">
<TextView
android:id="#+id/itemTextView"
android:layout_width="match_parent"
android:layout_height="?attr/listPreferredItemHeight"
android:gravity="center_vertical"
android:padding="8dp"
style="#style/Base.TextAppearance.AppCompat.Body2"/>
</android.support.v7.widget.CardView>
EDIT END
Doing a bit more research I found this question/answer which has a workaround to this problem. Although not ideal, it will have to do for now. Though the real solution shouldn't have to collapse the AppBarLayout, the scrolling should take into consideration the extra scrolling space needed. Perhaps this is just a bug that is overlooked.
In your addItem() method change this
notifyItemInserted(getItemCount() - 1);
to
notifyItemInserted(mItems.size() - 1);
This will solve the problem!
add this after adding item
notifyItemRangeChanged(0, items.size());
Have you tried
mRecyclerView.smoothScrollToPosition(mRecyclerView.getAdapter().getItemCount());
You can also put it in a runnable like this to make sure item has added before you scroll to it.
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
mRecyclerView.smoothScrollToPosition(mRecyclerView.getAdapter().getItemCount());
}
}, 1000);
Before you add list to adapter in Recycleview do some sorting by using Collection method according to your need,use this code may help you
Comparator<Long> comparator = Collections.reverseOrder();
Collections.sort(arrayList, comparator);

RecyclerView scrolling issue (Child items far away from each other)

Goodd day.I have simple recycler view with simplest dummy datas for test purpose,thus i have an weird issue to which the google did not find any solution or even an issue at all.On first launch the view is all good but as soon as i start to scrool,the child items are being as far from each other as no one can image...Really very and very far.But the issue is that the actual child items layout parameters are correct,only issue is that i dont know why RecyclerView decides to have each item heaps far away from each other.Please can you give me an help?Posting full code of my RecyclerView.
The view for recyclerView
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context="com.ink.activities.HomeActivity"
tools:showIn="#layout/app_bar_home">
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical" />
</RelativeLayout>
The Adapter.
public class FeedAdapter extends RecyclerView.Adapter<FeedAdapter.ViewHolder> {
private List<FeedModel> feedList;
private Context mContext;
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView title, content;
public ViewHolder(View view) {
super(view);
title = (TextView) view.findViewById(R.id.feedTitle);
content = (TextView) view.findViewById(R.id.feedContent);
}
}
public FeedAdapter(List<FeedModel> feedList, Context context) {
mContext = context;
this.feedList = feedList;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.feed_single_view, parent, false);
return new ViewHolder(itemView);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
FeedModel feedModel = feedList.get(position);
holder.title.setText(feedModel.getTitle());
holder.content.setText(feedModel.getContent());
// animate(holder);
}
public void animate(RecyclerView.ViewHolder viewHolder) {
final Animation animAnticipateOvershoot = AnimationUtils.loadAnimation(mContext, R.anim.bounce_interpolator);
viewHolder.itemView.setAnimation(animAnticipateOvershoot);
}
#Override
public int getItemCount() {
return feedList.size();
}
}
I guess you won`t need holder as no view initiated with it.
The single child item view of RecyclerView adapter.
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:clickable="true"
android:foreground="?android:attr/selectableItemBackground"
app:cardCornerRadius="5dp"
app:cardElevation="10dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/feedTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="10dp"
android:fontFamily="#string/appFont"
android:text="loading...."
android:textColor="#000000"
android:textSize="20sp" />
<TextView
android:id="#+id/feedContent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/feedTitle"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
android:layout_marginTop="10dp" />
</RelativeLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
The initiation of actual parameters.
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mAdapter = new FeedAdapter(mFeedModelArrayList, this);
RecyclerView.ItemAnimator itemAnimator = new DefaultItemAnimator();
itemAnimator.setAddDuration(500);
itemAnimator.setRemoveDuration(500);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.setItemAnimator(itemAnimator);
This code is as simple as it can get and it is important to mention that i am initiation all this inside the default NAVIGATION DRAWER ACTIVITY of android studio (the default templae inside content_main layout).So plaese can you give me any hint about the issue?
You're using
android:layout_width="match_parent"
android:layout_height="match_parent"
on your child item views. As of Support Library 23.2:
The RecyclerView widget provides an advanced and flexible base for creating lists and grids as well as supporting animations. This release brings an exciting new feature to the LayoutManager API: auto-measurement! This allows a RecyclerView to size itself based on the size of its contents. This means that previously unavailable scenarios, such as using WRAP_CONTENT for a dimension of the RecyclerView, are now possible. You’ll find all built in LayoutManagers now support auto-measurement.
Due to this change, make sure to double check the layout parameters of your item views: previously ignored layout parameters (such as MATCH_PARENT in the scroll direction) will now be fully respected.
Change your layout_height to wrap_content if you only want your items to be as large as needed. match_parent means they will be as large as the screen.

How to show images with horizontal scrolling android

I am using a Recyclerview to show the list of items. Now each time can have some photos/multiple photos which I need to show with horizontal scrolling in a single row.
I am currently using Gallery widget to show the photos but as it is now deprecated, so I want some other thing to use to show images horizontally with same features as Gallery have. Can you please help me here.
Thanks a lot in advanced.
Here is the example of horizontal scrollable RecycleView showing bitmap images:
fragment/activity layout:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
...
<android.support.v7.widget.RecyclerView
android:id="#+id/horizontal_recycler_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:layout_marginBottom="15dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:horizontalSpacing="10dp"
android:isScrollContainer="false"
android:stretchMode="columnWidth"
android:verticalSpacing="10dp"
/>
...
</LinearLayout>
item:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/horizontal_item_view_image"
android:layout_marginRight="10dp"
android:layout_width="109dp"
android:layout_height="109dp" />
</LinearLayout>
adapter:
public class HorizontalPhotosAdapter extends RecyclerView.Adapter<HorizontalPhotosAdapter.MyViewHolder> {
private Context context;
private LayoutInflater inflater;
private ArrayList<Bitmap> bitmapList;
public class MyViewHolder extends RecyclerView.ViewHolder {
private ImageView riv;
public MyViewHolder(View view) {
super(view);
riv = (ImageView) view.findViewById(R.id.horizontal_item_view_image);
}
}
public HorizontalPhotosAdapter(Context context, ArrayList<Bitmap> bitmapList, String[] imageUrls) {
this.context = context;
this.bitmapList = bitmapList;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.horizontal_item_view, parent, false);
if (itemView.getLayoutParams ().width == RecyclerView.LayoutParams.MATCH_PARENT)
itemView.getLayoutParams ().width = RecyclerView.LayoutParams.WRAP_CONTENT;
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
holder.riv.setImageBitmap(bitmapList.get(position));
}
#Override
public int getItemCount() {
return bitmapList.size();
}
}
implementation in fragment/activity:
horizontalAdapter=new HorizontalPhotosAdapter(getContext(), bitmapList);
horizontal_recycler_view.setAdapter(horizontalAdapter);
horizontalAdapter.notifyDataSetChanged();
LinearLayoutManager horizontalLayoutManagaer = new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false);
horizontal_recycler_view.setLayoutManager(horizontalLayoutManagaer);
horizontal_recycler_view.setAdapter(horizontalAdapter);
You can use HorizontalScrollView or ViewPager for your purpose.
Android Viewpager as Image Slide Gallery
You can use viewpager to implement slide show gallery
follow link -
http://codetheory.in/android-image-slideshow-using-viewpager-pageradapter/
A LayoutManager is responsible for measuring and positioning item views within a RecyclerView as well as determining the policy for when to recycle item views that are no longer visible to the user. By changing the LayoutManager a RecyclerView can be used to implement a standard vertically scrolling list, a uniform grid, staggered grids, horizontally scrolling collections and more. Several stock layout managers are provided for general use.
Try the below code to get recycler view with horizontal item
LinearLayoutManager ll_manager= new LinearLayoutManager(getActivity());
ll_manager.setOrientation(LinearLayoutManager.HORIZONTAL);
recyclerView.setLayoutManager(llmRecent);
You can also use the following piece of code:
GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 1);
gridLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
recyclerView.setLayoutManager(gridLayoutManager);

How to relayout RecyclerView after IME candidates is hidden?

I'm trying to make a chat-like screen with RecyclerView as this
However RecyclerView (LinearLayoutManager) doesn't works as I expected...
How can I fix or avoid this problem?
Detail:
The problem is also reproducible with very simplified Activity shown below.
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="0px"
android:layout_weight="1"
android:scrollbars="none"/>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
MainActivity.java
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initializeRecyclerView();
}
private void initializeRecyclerView() {
RecyclerView recycler = (RecyclerView) findViewById(R.id.recyclerview);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setReverseLayout(true);
recycler.setLayoutManager(layoutManager);
Adapter recyclerAdapter = new Adapter(createItemList());
recycler.setAdapter(recyclerAdapter);
}
private static ArrayList<String> createItemList(){
ArrayList<String> items= new ArrayList<>();
for(int i=0;i<20;i++){
items.add(String.format("item %02d",20-i));
}
return items;
}
}
RecyclerView is not completely relayout after IME candidates are hidden shown in this movie.
This problem is fixed by adding "adjustResize" into MainActivity's windowSoftInputMode, but I don't want to use it. Solution without changing windowSoftInputMode is wanted.
I had a similar problem. What will help you is creating a custom adapter which has a different viewholder and onbindview for the IME candidates. Then you can easily hide the IME candidates by changing LayoutView.Params and setting height to zero. This is how I've done it, sounds like a workaround but works for me. Hope this helps.

Categories

Resources