How delete a row of recycler view from ViewHolder - android

thanks to stop by.
Not a long time ago someone explain to me that you should'nt store data in ViewHolder, I get why. But then it complicate something.
I want to remove a Row if user click on a button inside the row. So i need to access adapter. But I can't store it on ViewHolder. What the way ?
I'am also looking for the best recyclerview article that you know because it look like people don't know what they talking about in most of the stack overflow and give bad advise (Store data inside ViewHolder)
EDIT : I'am trying one solution but getTag return me null when I'am in adapter
Here is my item and the binding :
public final class ItemViewMail extends RecyclerView.ViewHolder {
private AppCompatImageButton cancelButton;
public ItemViewMail(View itemView) {
super(itemView);
this.cancelButton = itemView.findViewById(R.id.profile_item_edit_email_cancel_image_button);
}
public void bind(Data data, View.OnClickListener deleteOnClickListener) {
this.itemView.setTag(data);
if (cancelButton != null) {
cancelButton.setOnClickListener(deleteOnClickListener);
}
}
}
My adapter :
private ArrayList<Data> rowDataArrayList;
MyPVPViewAdapter(ArrayList<Data> rowDataArrayList) {
this.rowDataArrayList = rowDataArrayList;
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int itemType) {
return new ItemViewMail(LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.profile_item_edit_email, viewGroup ,false));
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder myViewHolder, int position) {
((ItemViewMail) myViewHolder).bind((Data) rowDataArrayList.get(position).getData(), onClickListener);
}
#Override
public int getItemViewType(int position) {
return rowDataArrayList.get(position).getType();
}
#Override
public int getItemCount() {
return rowDataArrayList.size();
}
View.OnClickListener onClickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
Data data = (Data) v.getTag();
}
};
}

You can remove the item from the adapter and notify it about the removed row and it will update smoothly with the removal. Also remove the item from your data source, seems like you're doing that already though.
mAdapter.getItems().remove(mPosition);
mAdapter.notifyItemRemoved(mPosition);

data class MyItem(val name: String)
class MyViewHolder(itemView: View,
private val onRemoveClickListener: View.OnClickListener) : RecyclerView.ViewHolder(itemView) {
fun bind(item: MyItem) {
itemView.setOnClickListener(onRemoveClickListener)
itemView.setTag(item)
//todo: eg. itemView.name.setText(item.name)
}
}
class MyRecyclerViewAdapter(private val onRemoveClickListener: View.OnClickListener): RecyclerView.Adapter<MyViewHolder>() {
var items = listOf<MyItem>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.viewholder_my)
return MyViewHolder(view, onRemoveClickListener)
}
override fun getItemCount(): Int {
return items.size
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.bind(items[position])
}
}
Now you can create MyRecyclerViewAdapter inside your activity/fragment/etc and put onClickListener as a parameter.
class MyActivity: AppCompatActivity() {
private lateinit var adapter: MyRecyclerViewAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
adapter = MyRecyclerViewAdapter(View.OnClickListener { view ->
val clickedItem = view.getTag() as MyItem
adapter.items.remove(clickedItem)
adapter.notifyDataSetChanged()
})
}
}

I want to remove a Row if user clic on a button inside the row. So i need to access adapter. But I can't store it on ViewHolder. What the way ?
The base implementation of RecyclerView.ViewHolder provides two methods you can call when you need access to position information: getAdapterPosition() and getLayoutPosition(). In your case, it sounds like you want the first one.
This lets you write code like this:
public void soSomethingOnClick() {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
myDataStructure.removeItemAt(position);
myAdapter.notifyItemRemoved(position);
}
}
Not a long time ago someone explain to me that you should'nt store data in ViewHolder, I get why. But then it complicate something.
I'm not sure what you heard, but storing information in a ViewHolder is totally fine. You have to be careful to make sure you always update whatever data you're storing so that it doesn't get out of sync when a ViewHolder is recycled, but very many ViewHolder implementations take express advantage of the fact that ViewHolders are a great place to save data.

Related

notifyItemChanged call onCreateViewHolder

I've a strange problem with my recyclerView adapter, I just want to show/hide ImageView depending of the selection but when I call the notifyItemChanged(selection) in my click listener, it call onCreateViewHolder and take a delay to refresh de view, I don't know why and I didn't find another solution to perform what I need.
This is my adapter:
public class ChannelAdapter extends RecyclerView.Adapter<ChannelAdapter.ChannelHolder> {
private ArrayList<Integer> channelList;
private Integer selection = 0;
public ChannelAdapter(ArrayList<Integer> channelList) {
this.channelList = channelList;
}
#NotNull
#Override
public ChannelHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Log.d(TAG, "onCreateViewHolder: ");
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_channel_item_selected, parent, false);
ChannelHolder holder = new ChannelHolder(view);
return holder;
}
#SuppressLint("SetTextI18n")
#Override
public void onBindViewHolder(ChannelHolder holder, int position) {
Log.d(TAG, "onBindViewHolder: "+position);
holder.textViewChannelId.setText("#"+channelList.get(position));
holder.textViewChannel.setText(channelList.get(position).toString());
if(position==selection){
holder.imageViewSelectorLeft.setVisibility(View.VISIBLE);
holder.imageViewSelectorRight.setVisibility(View.VISIBLE);
}
else{
holder.imageViewSelectorLeft.setVisibility(View.INVISIBLE);
holder.imageViewSelectorRight.setVisibility(View.INVISIBLE);
}
}
#Override
public int getItemCount() {
return channelList.size();
}
public class ChannelHolder extends RecyclerView.ViewHolder {
TextView textViewChannel, textViewChannelId;
ImageView imageViewSelectorLeft, imageViewSelectorRight;
public ChannelHolder(View itemView) {
super(itemView);
textViewChannelId = itemView.findViewById(R.id.textViewChannelId);
textViewChannel = itemView.findViewById(R.id.textViewChannel);
imageViewSelectorLeft = itemView.findViewById(R.id.imageViewSelectorLeft);
imageViewSelectorRight = itemView.findViewById(R.id.imageViewSelectorRight);
itemView.setOnClickListener(v -> {
notifyItemChanged(selection);
selection=getAdapterPosition();
notifyItemChanged(selection);
});
}
}
}
Do I miss something or am I doing it by the wrong way?
Thanks in advance for any help
Edit :
I tried to use notifyItemChanged with a payload set to 1 and override onBindViewHolder to get the payload but it still call onCreateViewHolder, even when mSupportsChangeAnimations is set to false
By default, your RecyclerView will have a DefaultItemAnimator attached to it. When you call notifyItemChanged() on your adapter, the system will eventually call through to the DefaultItemAnimator to find out whether it needs to create a new ViewHolder or if it can "re-use" the existing one.
#Override
public boolean canReuseUpdatedViewHolder(#NonNull ViewHolder viewHolder,
#NonNull List<Object> payloads) {
return !payloads.isEmpty() || super.canReuseUpdatedViewHolder(viewHolder, payloads);
}
The superclass implementation:
#Override
public boolean canReuseUpdatedViewHolder(#NonNull RecyclerView.ViewHolder viewHolder) {
return !mSupportsChangeAnimations || viewHolder.isInvalid();
}
These suggest that there are two easy ways to make sure that the ViewHolder is reused instead of recreated:
Make sure that the payloads list is not empty. This is done by calling adapter.notifyItemChanged(position, payload). It doesn't matter what the payload is, as long as it is non-null.
Set mSupportsChangeAnimations to false for your DefaultItemAnimator.
DefaultItemAnimator animator = (DefaultItemAnimator) recyclerView.getItemAnimator();
animator.setSupportsChangeAnimations(false);
You can call your adapter like this
YourAdapter adapter = new YourAdapter(yourList, yourActivity.this);
recyclerView.setAdapter(adapter);
adapter.notifyDataSetChanged();
and then you can put this code on itemClick in adapter
if(position==getAdapterPosition()){
holder.imageViewSelectorLeft.setVisibility(View.VISIBLE);
holder.imageViewSelectorRight.setVisibility(View.VISIBLE);
}
else{
holder.imageViewSelectorLeft.setVisibility(View.INVISIBLE);
holder.imageViewSelectorRight.setVisibility(View.INVISIBLE);
}

How to use bind function of groupie library in java?

I am trying to show a list of user in recyclerView and trying to connect the textview layout in bind method in groupie library and i don't know how to link the id of layout to recyclerview viewHolder? and also how to use picasso library in viewholder?
private void fetchUser(){
DatabaseReference fireBaseReference = FirebaseDatabase.getInstance().getReference().child("/userList");
fireBaseReference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
GroupAdapter groupA = new GroupAdapter<ViewHolder>();
for (DataSnapshot snapshot : dataSnapshot.getChildren()){
Log.d("userList",snapshot.toString());
Users string = snapshot.getValue(Users.class);
groupA.add(new UserItem());
}
recyclerView.setAdapter(groupA);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
}
class UserItem extends Item<ViewHolder>{
// public UserItem(Users users){
// }
private Users users = new Users();
#Override
public void bind(#NonNull ViewHolder viewHolder, int position) {
viewHolder.itemView.findViewById(R.id.user_name_from_user_list);
viewHolder.
Picasso.get().load(users.getUri()).into(viewHolder.itemView.findViewById(R.id.user_photo_from_user_list));
}
#Override
public int getLayout() {
return R.layout.user_list_view_layout;
}
}
Groupie abstracts away the complexity of multiple item view types. Each Item declares a view layout id, and gets a callback to bind the inflated layout. That's all you need; you can add your new item directly to a GroupAdapter and call it a day.
Item with Kotlin
The Item class gives you simple callbacks to bind your model object to the generated fields. Because of Kotlin Android extensions, there's no need to write a view holder.**
class SongItem(private val song: Song) : Item() {
override fun getLayout() = R.layout.song
override fun bind(viewHolder: GroupieViewHolder, position: Int) {
viewHolder.title.text = song.title
viewHolder.artist.text = song.artist
}
}
Item with data binding:
The Item class gives you simple callbacks to bind your model object to the generated binding. Because of data binding, there's no need to write a view holder.
If you're converting existing ViewHolders, you can reference any named views (e.g. R.id.title) directly from the binding instead.
#Override public void bind(SongBinding binding, int position) {
binding.title.setText(song.getTitle());
}
or you can do this way
#Override
public void bind(#NonNull final ViewHolder viewHolder, final int position) {
circleImageView = viewHolder.itemView.findViewById(R.id.circleImageViewForLatestMessage);
userMessage = viewHolder.itemView.findViewById(R.id.textView2);
userName = viewHolder.itemView.findViewById(R.id.textView41);
userName.setText(name);
userMessage.setText(messages);
You can also mix and match BindableItem and other Items in the adapter, so you can leave legacy viewholders as they are by making an Item.
For more information visit Groupie Library

Implement onItemClickListener using MVP pattern

I am learning MVP and got confused where and how should I implement onClickListener while not ruining mvp concept here.
Followed this guide: https://android.jlelse.eu/recyclerview-in-mvp-passive-views-approach-8dd74633158
My implementation.
Adapter:
public class RepositoriesRecyclerAdapter extends RecyclerView.Adapter<RepositoriesRecyclerAdapter.RepoViewHolder> {
private final RepositoriesListPresenter presenter;
public RepositoriesRecyclerAdapter(RepositoriesListPresenter repositoriesPresenter) {
this.presenter = repositoriesPresenter;
}
#Override
public RepositoryViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new RepositoryViewHolder(LayoutInflater.from(parent.getContext())
.inflate(R.layout.cell_repo_view, parent, false));
}
#Override
public void onBindViewHolder(RepositoryViewHolder holder, int position) {
presenter.onBindRepositoryRowViewAtPosition(position, holder);
}
#Override
public int getItemCount() {
return presenter.getRepositoriesRowsCount();
}
}
RepositoryViewHolder's
public class RepositoryViewHolder extends RecyclerView.ViewHolder implements RepositoryRowView {
TextView titleTextView;
TextView starsCountTextView;
public RepositoryViewHolder(View itemView) {
super(itemView);
titleTextView = itemView.findViewById(R.id.repoTitleText);
starsCountTextView = itemView.findViewById(R.id.repoStarsCountText);
}
#Override
public void setTitle(String title) {
titleTextView.setText(title);
}
#Override
public void setStarCount(int starCount) {
starsCountTextView.setText(String.format("%s ★", starCount));
}
}
RepositoryRowView
interface RepositoryRowView {
void setTitle(String title);
void setStarCount(int starCount);
}
All guides I saw was about creating onClickListener object in Adapter and then use it in ViewHolder, but in this implementation, I override all adapter function in my presenter and passing onClickListener (android related stuff) would contradict mvp pattern. What to do in this case. Maybe someone could write a solution - really confused.
My main goal would be to click a recyclerview item and get item name (via toast)
OnClickListener is an interface from Android SDK. Your presenter should not know anything about the Andriod SDK. It should be pure Java so it can be tested just by using Unit test on the JVM. It shouldn't know anything about views, RecyclerView, Adapter nor ViewHolder.
Your onBindViewHolder doesn't violate this principle because it's separated by an abstract interface - RepositoryRowView.
You should implement OnClickListener in adapter/viewholder and call your presenter from there.
public class RepositoryViewHolder extends RecyclerView.ViewHolder implements RepositoryRowView, View.OnClickListener {
TextView titleTextView;
TextView starsCountTextView;
RepositoriesListPresenter presenter;
public RepositoryViewHolder(View itemView, RepositoriesListPresenter presetner) {
super(itemView);
titleTextView = itemView.findViewById(R.id.repoTitleText);
starsCountTextView = itemView.findViewById(R.id.repoStarsCountText);
this.presenter = presenter;
itemView.setOnClickListener(this);
}
#Override
public void setTitle(String title) {
titleTextView.setText(title);
}
#Override
public void setStarCount(int starCount) {
starsCountTextView.setText(String.format("%s ★", starCount));
}
#Override
public void onClick(View view) {
if (presenter != null) {
presenter.onItemInteraction(getAdapterPosition());
}
}
}
Instead of calling the presenter inside your adapter, I would rather make an interface of the click to call it from the view, since you will instantiate this adapter in your view, it's a good thing to keep the MVP pattern with the click of the elements inside your view and not in the adapter itself.
This example is in Kotlin, but I'm sure you will understand it.
First, just make a simple interface to call your click event whenever the user clicks on any item in your list.
class EquipmentAdapter(private val context: Context,private var equipmentList:ArrayList<Equipment>,itemListener:RecyclerViewClickListener): RecyclerView.Adapter<EquipmentAdapter.EquipmentViewHolder>() {
interface RecyclerViewClickListener {
fun recyclerViewListClicked(v: View?, position: Int)
}
companion object{
var itemClickListener: RecyclerViewClickListener? = null
var equipmentSearchList:ArrayList<Equipment>? = null
}
init {
equipmentSearchList = equipmentList
itemClickListener = itemListener
}
Then , inside your ViewHolder you should call this interface to handle the click
inner class EquipmentViewHolder(itemView: View): RecyclerView.ViewHolder(itemView), View.OnClickListener {
val equipmentName:TextView = itemView.txt_equipmentname
init {
itemView.setOnClickListener(this)
}
override fun onClick(v: View?) {
itemClickListener?.recyclerViewListClicked(v, adapterPosition)
}
}
Lastly, just implement the interface of the click in the view that you are calling the adapter, and then just manage the presenter interactions there instead inside the adapter
class EquipmentActivity : BaseActivity(), EquipmentContract.EquipmentView, EquipmentAdapter.RecyclerViewClickListener ...
And implement the click method
override fun recyclerViewListClicked(v: View?, position: Int) {
presenter.onItemInteraction(position)
}
Doing this, you are making sure that the click of the elements in the list are being made from the view itself and not from the adapter, here, you can interact with the presenter as always and also do more things that will keep your project clean.

How to implement Infinite Scrolling with RecyclerView?

I have a recycler and inside of it there are cardviews where I fetch information from a REST service, I'm trying to implement an endless scroll, It's supposed that user will see 10 cardviews every time he scrolls down until there are no more cardviews to show, How can I achieve that?
I've seen a few examples but none of them really helped me about how to do it. I don't even know what I need to put in adapter.class or in my Fragment.class because I don't understand how to implement that, it would be great if someone could tell me the correct way to implement the infinite scroll in my code...
Thanks in advance.
MainAdapter.class
public class MainAdapter extends RecyclerView.Adapter<MainAdapter.ViewHolder> implements View.OnClickListener
{
private ArrayList<Business> businessList;
private Activity activity;
private int layoutMolde,idb;
public MainAdapter(Activity activity, ArrayList<Business> list, int layout)
{
this.activity = activity;
this.businessList = list;
layoutMolde = layout;
}
#Override
public MainAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.main_row, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position)
{
holder.mTitle.setText(businessList.get(position).getBusiness_name());
holder.number_rating.setText(businessList.get(position).getRating().toString());
Glide.with(activity).load(businessList.get(position).getLogo_url_string()).into(holder.mImg);
}
#Override
public int getItemCount() {
return businessList.size();
}
#Override
public void onClick(View v)
{
}
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView mTitle;
public ImageView mImg;
public ImageView logo;
public RatingBar main_rating;
public TextView number_rating;
public ViewHolder( View itemView)
{
super(itemView);
mTitle = (TextView) itemView.findViewById(R.id.nom_business_main);
number_rating = (TextView) itemView.findViewById(R.id.number_rating);
mImg = (ImageView) itemView.findViewById(R.id.img_main);
main_rating=(RatingBar) itemView.findViewById(R.id.rating_main);
main_rating.setRating((float)1);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v)
{
Intent in = new Intent(v.getContext(), BusinessPremium.class);
int position = getAdapterPosition();
idb = businessList.get(position).getId();
in.putExtra("no", idb);
v.getContext().startActivity(in);
}
});
}
}
}
FeedsFragment.class
public class FeedsFragment extends Fragment
{
private ArrayList<Business> arrayBusiness,arrayBasics;
private Gson gson;
private static final Type BUSINESS_TYPE = new TypeToken<ArrayList<Business>>() {}.getType();
private RecyclerView.LayoutManager mLayoutManager;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View android = inflater.inflate(R.layout.fragment_feeds, container, false);
if (!internetConnectionCheck(FeedsFragment.this.getActivity()))
{
Toast.makeText(getApplicationContext(), "Error de Conexión", Toast.LENGTH_LONG).show();
}
new RequestBase(getActivity()) {
#Override
public JsonObject onHttpOk(JsonObject response) throws JSONException {
JsonObject objeto, pagination_details = null, details, premium_img;
JsonArray data;
if (getActivity() == null)
return response;
if (response.get("pagination") == null)
{
objeto = response;
} else {
objeto = response;
pagination_details = response.get("pagination").getAsJsonObject();
data = objeto.get("data").getAsJsonArray();
gson = new Gson();
arrayBusiness = gson.fromJson(data, BUSINESS_TYPE);
Log.d("size", String.valueOf(arrayBusiness.size()));
FeedsFragment.this.getActivity().runOnUiThread(new Runnable()
{
#Override
public void run()
{
RecyclerView recycler = (RecyclerView) FeedsFragment.this.getActivity().findViewById(R.id.recycler_main);
MainAdapter adapter = new MainAdapter(getActivity(), arrayBusiness, R.layout.main_row);
recycler.setNestedScrollingEnabled(false);
mLayoutManager = new GridLayoutManager(FeedsFragment.this.getActivity(), 2);
recycler.setLayoutManager(mLayoutManager);
recycler.setAdapter(adapter);
GifTextView loading = (GifTextView)FeedsFragment.this.getActivity().findViewById(R.id.loading);
TextView loadingText = (TextView)FeedsFragment.this.getActivity().findViewById(R.id.loadingText);
loading.setVisibility(View.GONE);
loadingText.setVisibility(View.GONE);
}
});
}
if (pagination_details.isJsonNull()) {
Log.d("Paginacion", pagination_details.toString());
}
return objeto;
}
#Override
public void onHttpCreate(JsonObject response) throws JSONException
{
}
#Override
public void onHttpUnprocessableEntity(JsonObject response) throws JSONException
{
this.cancel(true);
final String error = response.get("errors").toString();
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getActivity().getApplicationContext(), error, Toast.LENGTH_LONG).show();
}
});
}
}.execute("businesses/premiums", "GET");
return android;
}
}
you can refresh using SwipeRefreshLayout in android to refresh and in the on refresh override method call your api
note:put your API call request in a method and call that method inyour onRefresh method of SwipeRefreshLayout
When writing RecyclerView.Adapter, you anyway need to provide the getItemCount method that returns the correct number of items (may be large). RecyclerView will call on its own initiative the onBindViewHolder(holder, position) method of this adapter. All you need is to provide functionality of retrieving data, relevant to this position. There is no difference at all, if your list is smaller than screen, slightly larger than screen or Integer.MAX_VALUE size. RecyclerView will take care not to fetch/allocate too much extra items.
You do not need to implement scroll listeners or otherwise explicitly handle the scrolling.
The only tricky part is that you may need to take a long action like server call to get some items. Then just return uninitialized holder (empty view) on the first invocation and start fetching the needed row in the background thread. When you have it, call notifyDataSetChanged or notifyItemRangeChanged, and RecyclerView will take care to update itself.
For performance reasons I would strongly recommend to update content in chunks of the fixed size rather than sending individual server request per every row displayed. For some public servers like Google Books this is clearly a requirement, as they have quota limits per request.
If you need to view the full source code on how this possibly could be implemented, there is an open source project here in GitHub.
Make a static boolean variable named "ready" and initialize it to false.
Add the if ready condition in the onLoadMore method as below.
public boolean onLoadMore(int page, int totalItemsCount) {
if (ready) {
//load more from API
}
return false;
}
set ready to true in onBindViewHolder when the position of item is last.
Here is a way that a colleague of mine introduced. we worked in it together and i implemented it successfully with no issues. I wanted to give back to anyone having this issue.
in your adapter you need to set the count to be infinite size and then when you want the position of an item you should use val loopPos = position % dataSource.size anytime you need the position. lets take a look how this can be done in a recyclerView adapter but could also be applied to FragmentStatePagerAdapter.
class InfiniteLoopingHorizontalRecyclerViewAdapter(var dataSource: ArrayList<String>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val inflatedView: View = LayoutInflater.from(parent.context)
.inflate(R.layout.your_finite_layout, parent, false)
return ItemHolder(inflatedView)
}
override fun getItemCount(): Int {
return Integer.MAX_VALUE //***** this should be high enough - wink wink ******
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
//****** this is critical here when you need the position use the loopPos ****/
val loopPos = position % dataSource.size
(holder as? ItemHolder)?.bind(dataSource[loopPos], loopPos)
}
inner class ItemHolder(view: View) : RecyclerView.ViewHolder(view) {
fun bind(myString: String, position: Int) = with(itemView) {
myTextView.setText(myString)
}
}
}
how it works:
lets say your dataSource size is 50 but your position is at 51 that means the following: 51%50 . which gives you position 1. and lets say again your position is 57 and again your dataSource size is still 50. that means your position is 7. so to be clear, anytime you need a infinite affect you can use the modules of the position and the dataSource size.
ps:
lets go crazy and say we scrolled to position 11323232323214 then that means 11323232323214%50 = 14 so its position 14 in your datasource that will be used. you can then polish off the affect with wrapping your recyclerview in a SnapHelper class
You can add a scrollListener to your recyclerview.
Check a similar answer here
And the main SO post here
Where, the scrollListener will check where exactly are you in the recyclerview and based on some logic (which you can flexibly write) make a second call!

setOnItemClickListener not getting called

I have this in the onCreate method as follows:
ListView lv = (ListView)findViewById(android.R.id.list);
adapter = new ModuleAdapter(this);
lv.setAdapter(adapter);
lv.setOnItemClickListener(this);
Then later in the code:
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
// TODO Auto-generated method stub
Log.v(TAG, "clicked");
}
OnItemClickListener is being implemented.
I'm trying to fire a new activity from onItemClick but it does not appear to be working.
New to Android and don't know a lot of java. Can anyone help? Thanks.
Do you set FocusableInTouchMode to be true in your layout? If so then onItemClick will not be called.
Try this changes in the xxx_row.xml
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:enabled="false">
</TextView>
At least for me it worked when i changed the width and enabled attributes.
ListView lv = (ListView)findViewById(android.R.id.list);
It's if you trying to get android System resources, but you want listview which you describe on xml layout.
Let's say it's look like:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ListView
android:id="#+id/listView1"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
</ListView>
</LinearLayout>
so you need change your code to
ListView lv = (ListView)findViewById(R.id.listView1);
Some explain:
android.R - it's default resources of Android OS - llike
buttons,images, listview items layouts and etc.
R - it' your project resoures full path likes [your package path].R
for example: com.example.R
I am not sure if what you are trying to do is intentional. You are setting click listener on the whole list view container. I believe you wanted to set a click listener for the items inside. I will give you an example below, but also please note that I am extending RecyclerView here instead of using ListView which is rather obsolete.
Java version:
public class ModuleAdapter2 extends RecyclerView.Adapter<ModuleAdapter2.ItemViewHolder> {
private final List<Item> items;
private final ModuleAdapterListener listener;
public ModuleAdapter2(List<Item> items, ModuleAdapterListener listener) {
this.items = items;
this.listener = listener;
}
public static class ItemViewHolder extends RecyclerView.ViewHolder {
public ItemModuleBinding binding;
public ItemViewHolder(ItemModuleBinding binding) {
super(binding.getRoot());
this.binding = binding;
}
}
#NonNull
#Override
public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
ItemModuleBinding binding = ItemModuleBinding.inflate(inflater, parent, false);
return new ItemViewHolder(binding);
}
#Override
public void onBindViewHolder(ItemViewHolder holder, int position) {
Item item = items.get(position);
holder.binding.getRoot().setOnClickListener(v -> listener.onItemClicked(item));
}
#Override
public int getItemCount() {
return items.size();
}
interface ModuleAdapterListener {
void onItemClicked(Item item);
}}
Kotlin version:
class ModuleAdapter(var items: MutableList<Item>, private val listener: ModuleAdapterListener) : RecyclerView.Adapter<ModuleAdapter.ItemViewHolder>() {
inner class ItemViewHolder(val binding: ItemModuleBinding) : RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder {
val inflater = LayoutInflater.from(parent.context)
val binding = ItemModuleBinding.inflate(inflater, parent, false)
return ItemViewHolder(binding)
}
override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
holder.binding.root.setOnClickListener {
listener.onItemClicked(items[position])
}
}
override fun getItemCount(): Int {
return items.size
}
interface ModuleAdapterListener {
fun onItemClicked(item: Item)
}}
If by any chance you wanted to use the click listener for the container, the reason why it is not working for you, is that the container is consuming the click within the onTouch method (and that is why you are not getting your onClick events). If you would like to overcome this, find some good solutions in both Java and Kotlin here: setOnClickListener for recyclerView not working

Categories

Resources