LinearLayoutManager - repetition in a circle - android

Is there any easy way to make LinearLayoutManager to be as a circle (repetition items in a circle)?
I investigated it and found only way to make own custom LayoutManager, so it would be cool to find a way with less code

First thing to do is change your adapter's getItemCount() method to return Integer.MAX_VALUE. This is not actually infinite, but it's over two billion so I doubt anyone's going to scroll that far.
Next, whenever you retrieve an item from your data source, don't just use position. Instead, use position % dataSource.size()... this will repeat your items as the user scrolls.
Here's an example:
public class MainActivity extends AppCompatActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RecyclerView recycler = (RecyclerView) findViewById(R.id.recycler);
recycler.setAdapter(new MyAdapter());
}
private static class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {
private final List<String> items;
private MyAdapter() {
items = new ArrayList<>();
items.add("A");
items.add("B");
items.add("C");
items.add("D");
}
#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) {
String item = items.get(position % items.size());
((TextView) holder.itemView).setText(item);
}
#Override
public int getItemCount() {
return Integer.MAX_VALUE;
}
}
private static class MyViewHolder extends RecyclerView.ViewHolder {
public MyViewHolder(View itemView) {
super(itemView);
}
}
}

Related

Make ItemTouchHelper run OnMove only when I release my touch on a RecyclerView List

I have a basic RecyclerView list and added a ItemTouchHelper in order to drag and drop list items.
The problem I have with it is that it runs onMove on every single list item it passes and it's lagging the app real hard.
Is there a way to implement it so that onMove only runs when I release my hold on a RecyclerView list item?
Thanks.
MainActivity.java
public class pillar_sort extends AppCompatActivity {
private MyRecyclerViewAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
// Initialize layout
super.onCreate(savedInstanceState);
setContentView(R.layout.pillar_sort);
final SharedPreferences sharedPref = // Get SharedPreferences
final ArrayList<String> modules = // Import a list
final ArrayList<Boolean> visibility = // Import a list
RecyclerView recyclerView = findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
adapter = new MyRecyclerViewAdapter(this, modules, visibility, cardcolor, txtcolor);
recyclerView.setAdapter(adapter);
VerticalSpaceItemDecoration decor = new VerticalSpaceItemDecoration();
recyclerView.addItemDecoration(decor);
ItemTouchHelper helper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP|ItemTouchHelper.DOWN, 0) {
#Override
public boolean onMove(#NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder dragged, #NonNull RecyclerView.ViewHolder target) {
int position_dragged = dragged.getAdapterPosition();
int position_target = target.getAdapterPosition();
Collections.swap(modules,position_dragged,position_target);
adapter.notifyItemMoved(position_dragged,position_target);
adapter.notifyDataSetChanged();
return false;
}
#Override
public void onSwiped(#NonNull RecyclerView.ViewHolder viewHolder, int direction) {
}
});
helper.attachToRecyclerView(recyclerView);
}
MyRecyclerViewAdapter.java
public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ViewHolder> {
// Variables go here
MyRecyclerViewAdapter( /* a lot of data to pass onto the adapter */ ) {
// get data from MainActivity and put on variables
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.recyclerview_row, parent, false);
CardView card = view.findViewById(R.id.card);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(final ViewHolder holder, final int position){
// Put data to TextViews and set card color
}
#Override
public int getItemCount() {
return modules.size();
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView myTextView;
ImageButton image_visibility;
ViewHolder(View itemView) {
super(itemView);
myTextView = itemView.findViewById(R.id.rowText);
image_visibility = itemView.findViewById(R.id.imageButton);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
}
}

Different viewtypes in recyclerview with GridLayoutManager

I know many have asked this question before, I too have in fact I have worked on a chat app that uses a recyclerview to show chats, I use view types pick a message layout depending on the sender but I feel this question is different.
I have a Recyclerview which is displaying content with a GridLayoutManager
heres an image to show that, in my image I have 3 items; A, B and C, I would like C to fit the width, I am really not sure if this can be achieved with view types, below is my Adapter code
Adapter:
public class StoreDisplayItemAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context context;
private ArrayList<StoreDisplayProduct> products;
private Interfaces.OnItemClickedListener onItemClickedListener;
public StoreDisplayItemAdapter(Context context, ArrayList<StoreDisplayProduct> products, Interfaces.OnItemClickedListener onItemClickedListener) {
this.context = context;
this.products = products;
this.onItemClickedListener = onItemClickedListener;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
return new ItemViewHolder(inflater.inflate(R.layout.store_display_item, parent, false));
}
public StoreDisplayProduct getProductsItem(int pos) {
return products.get(pos);
}
public void setProducts(ArrayList<StoreDisplayProduct> products) {
this.products = products;
notifyDataSetChanged();
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
StoreDisplayProduct product = getProductsItem(position);
ItemViewHolder viewHolder = (ItemViewHolder) holder;
viewHolder.txtProductType.setText(product.getProductTypeDisplayName());
viewHolder.txtName.setText(product.getName());
viewHolder.img.post(() -> Picasso.with(context)
.load(product.getDisplayImage().getFullSize())
.fit()
.transform(new RoundedCornersTransformation(10,10))
.placeholder(R.color.asbestos)
.centerCrop()
.into(viewHolder.img));
}
#Override
public int getItemCount() {
return this.products.size();
}
public class ItemViewHolder extends RecyclerView.ViewHolder {
#BindView(R.id.txtProductType)
TextView txtProductType;
#BindView(R.id.img)
SquareImageView img;
#BindView(R.id.txtName)
TextView txtName;
public ItemViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
itemView.setOnClickListener(v -> {
onItemClickedListener.onItemClicked(v, getAdapterPosition());
});
}
}
}
And how I use the adapter
recyclerStoreDisplayProducts.setAdapter(storeDisplayItemAdapter);
recyclerStoreDisplayProducts.setLayoutManager(new GridLayoutManager(getContext(), 2));
recyclerStoreDisplayProducts.setHasFixedSize(true);
recyclerStoreDisplayProducts.setNestedScrollingEnabled(true);
You can use span count like
GridLayoutManager layoutManager = new GridLayoutManager(this, 4);
layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
#Override
public int getSpanSize(int position) {
if (position<3)
return 1;
else
return 2;
}
});
You can use the Staggered Grid Layout Manager as per your question #Aubry,
//you need to add the code for creating a staggered layout manager
recyclerStoreDisplayProducts.setAdapter(storeDisplayItemAdapter);
StaggeredGridLayoutManager staggeredGridLayoutManager = new
StaggeredGridLayoutManager(mNoOfColumns,StaggeredGridLayoutManager.HORIZONTAL);
recyclerStoreDisplayProducts.setHasFixedSize(true);
recyclerStoreDisplayProducts.setNestedScrollingEnabled(true);
recyclerStoreDisplayProducts.setLayoutManager(staggeredGridLayoutManager);

nested recyclerview inside adapter

I am developing an android app where I have used nested RecyclerView but I am not achieving what I want.I want to achieve on this list it should show Title and below multiple images like json below how can I achieve that I am using two viewholder and it should scrool as well.
json structure
below Adapter class
public class UranAdapter extends RecyclerView.Adapter {
public List<Exhibit> exhibitList;
public Context context;
public UranAdapter(List<Exhibit> uranList, Context context) {
this.exhibitList = uranList;
this.context = context;
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View itemView;
switch (viewType) {
case Exhibit.TEXT_TYPE:
itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.exhibit_list, parent, false);
return new ViewHolder(itemView);
case Exhibit.IMAGE_TYPE:
itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.exhibit_list2, parent, false);
return new ImageViewHolder(itemView);
}
return null;
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder viewHolder, int i) {
}
#Override
public int getItemViewType(int position) {
return exhibitList.get(position).type;
}
public int getItemCount() {
return exhibitList.size();
}
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
Exhibit exhibit = exhibitList.get(position);
switch (exhibit.type) {
case Exhibit.TEXT_TYPE:
((ViewHolder) holder).exhibition_textView.setText(exhibit.getTitle());
break;
case Exhibit.IMAGE_TYPE:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
((ViewHolder) holder).exhibition_imageView.setImageResource(exhibit.image);
}
break;
}
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public ImageView exhibition_imageView;
TextView exhibition_textView;
public ViewHolder(View view) {
super(view);
exhibition_textView = (TextView) view.findViewById(R.id.exhibition_textview);
}
}
public static class ImageViewHolder extends RecyclerView.ViewHolder {
public ImageView exhibition_imageView;
TextView exhibition_textView;
public ImageViewHolder(View view) {
super(view);
exhibition_imageView = (ImageView) view.findViewById(R.id.exhibition_imageview);
}
}
}
below MainActivity
public class MainActivity extends AppCompatActivity {
public List<Exhibit> exhibitList = new ArrayList<>();
Context context;
RecyclerView recyclerView;
public UranAdapter uranAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ApiInterface apiInterface = ApiClient.getApiService();
Call<ExhibitsLoader> call = apiInterface.getExhibitList();
call.enqueue(new Callback<ExhibitsLoader>() {
#Override
public void onResponse(Call<ExhibitsLoader> call, Response<ExhibitsLoader> response) {
exhibitList = response.body().getExhibitList();
exhibitList.add(new Exhibit(Exhibit.IMAGE_TYPE));
RecyclerView recyclerView = findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
uranAdapter = new UranAdapter(exhibitList, context); // changes
recyclerView.setAdapter(uranAdapter);
}
#Override
public void onFailure(Call<ExhibitsLoader> call, Throwable t) {
}
});
}
}
below image what I want
I think what you need here is flatMap the embedded image list into one-level list and you're going correctly to have two ViewHolder of different types, one for title, and one for image. Don't understand why your ViewHolders are static.
You forget to call notifyDatasetChanged() after setting the adapter.
uranAdapter = new UranAdapter(exhibitList, context); // changes
recyclerView.setAdapter(uranAdapter);
uranAdapter.notifyDatasetChanged();
Use Expandable CardView for this ..
Like : https://www.youtube.com/watch?v=z9qScBaKfnM&t=727s
Why don't you use two RecyclerViews, one inside the other?
One RecyclerView will have the title and a children RecyclerView. The second RecyclerView(the children RecyclerView) will have just the images.
Check this post: Recyclerview inside Recyclerview , get click position of child row inside parent Adapter

RecyclerView, slow scrollToPosition, setSelected

Prompt, faced with scrollToPosition speed. I RecyclerView 900 positions and need to quickly establish a position as scrollToPosition very slow, c ListView such problems were not setSelection working out perfectly. It is possible to accelerate the scrollToPosition?
public class EventAdapter extends RecyclerView.Adapter<EventAdapter.Holder> {
final static public String TAG = "EventAdapter";
Context context;
List<Event> items;
public EventAdapter(List<Event> items) {
this.items = items;
}
#Override
public EventAdapter.Holder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_list_event, parent, false);
context = parent.getContext();
return new EventAdapter.Holder(v);
}
#Override
public void onBindViewHolder(EventAdapter.Holder holder, int position) {
holder.setModel(context, items.get(position), position);
}
#Override
public int getItemCount() {
return items.size();
}
public class Holder extends RecyclerView.ViewHolder {
public View block;
Holder(View view) {
super(view);
block = (View) view.findViewById(R.id.cv);
}
public void setModel(Context context, Event model, int position) {
}
}
}
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
rv.setLayoutManager(linearLayoutManager);
rv.setHasFixedSize(true);
linearLayoutManager.scrollToPosition(index);
There are couple of ways to do it:
1) Try smoothScrollToPosition as : [will certainly work]
Toast.makeText(this, "Scroll...", Toast.LENGTH_SHORT).show();
myList.smoothScrollToPosition(0);
2) Also read about scrollToPositionWithOffset as this may help too

Selected image in recyclerview is get unselected upon scroll

In my recyclerview has one imageview and textview. I'm changing image of ImageView onn onClickListener. Now the problem is if i click on image of position 3 and scroll down... image of position 8 is also changed and again if i scroll up...image of position 2 is changed.
public class PortraitListviewAdapter extends RecyclerView.Adapter<PortraitListviewAdapter.ViewHolder> {
Context context;
static List<PortraitParentListAdapterBean> list;
static List<String> selectedPosition ;
public PortraitListviewAdapter(Context context, List<PortraitParentListAdapterBean> list) {
this.context = context;
this.list = list;
selectedPosition = new ArrayList<>();
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.listview_parent_portrait, parent, false);
return new ViewHolder(itemView);
}
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
PortraitParentListAdapterBean portBean = list.get(position);
Log.i("pos",position+"");
holder.parentHeading.setText(portBean.getHeading());
if (selectedPosition.contains(list.get(position).getHeading())){
holder.parentImage.setImageResource(R.drawable.sad);
}
}
#Override
public int getItemCount() {
return list.size();
}
static class ViewHolder extends RecyclerView.ViewHolder {
protected TextView parentHeading;
protected ImageView parentImage;
public ViewHolder(View itemView) {
super(itemView);
parentHeading = (TextView)itemView.findViewById(R.id.parent_heading);
parentImage = (ImageView)itemView.findViewById(R.id.imageView);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
selectedPosition.add(list.get(getAdapterPosition()).getHeading());
parentImage.setImageResource(R.drawable.sad);
}
});
}
}
}
the above code is my implementation for recyclerview adapter. please help to understand the concept.
SOLUTION
change
if (selectedPosition.contains(list.get(position).getHeading())){
holder.parentImage.setImageResource(R.drawable.sad);
}
with
if (selectedPosition.contains(list.get(position).getHeading())){
holder.parentImage.setImageResource(R.drawable.sad);
} else {
holder.parentImage.setImageResource(R.drawable.your_default_drawable);
}
EXPLANATION
When you scroll your RecyclerView the system doesn't recreate always your ViewHolder but reuse one you previously scrolled that is no longer visible, so you need to reset your standard values in order to avoid showing wrong values.

Categories

Resources