I have an expandable RecyclerView, when the data is loaded in the Recyclerview everything seems good but when I scroll to the bodem, the data on the items above were muted to. In a normale recycler view I can solve this problem by bind everything in my OnBindViewHolder but now its harder.
this is my code for the expandable adapter:
public class CalendarAdapter extends ExpandableRecyclerViewAdapter<CalendarHeaderViewHolder, CalendarItemViewHolder> {
private Context ctx;
public CalendarAdapter(List<? extends ExpandableGroup> group, Context ctx){
super(group);
this.ctx = ctx;
}
#Override
public CalendarHeaderViewHolder onCreateGroupViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.group_view_holder, parent, false);
return new CalendarHeaderViewHolder(view);
}
#Override
public CalendarItemViewHolder onCreateChildViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.calendar_item, parent, false);
return new CalendarItemViewHolder(view,ctx);
}
#Override
public void onBindChildViewHolder(CalendarItemViewHolder holder, int flatPosition, ExpandableGroup group, int childIndex) {
final CalenderItem calenderItem = ((CalenderHeader) group).getItems().get(childIndex);
holder.onBind(calenderItem, group);
}
#Override
public void onBindGroupViewHolder(CalendarHeaderViewHolder holder, int flatPosition, ExpandableGroup group) {
holder.setGroupName(group);
}
}
And i bind my Holder in CalendarItemViewHolder
public class CalendarItemViewHolder extends ChildViewHolder {
private TextView tvDescription;
private TextView tvSubDescription;
private TextView tvDate;
private RelativeLayout ivIcon;
private CalenderItem item;
private LinearLayout llItemCal;
private onInteractionListener listener;
private Context ctx;
public CalendarItemViewHolder(View itemView, Context ctx){
super(itemView);
tvDescription = (TextView) itemView.findViewById(R.id.tvDescription);
tvSubDescription = (TextView)itemView.findViewById(R.id.tvSubDescription);
ivIcon = (RelativeLayout) itemView.findViewById(R.id.ivIcon);
tvDate = (TextView) itemView.findViewById(R.id.tvDate);
llItemCal = (LinearLayout) itemView.findViewById(R.id.llItemCal);
this.ctx = ctx;
listener = (onInteractionListener) ctx;
}
public void onBind(CalenderItem calenderItem, ExpandableGroup group){
this.item = calenderItem;
llItemCal.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//MOVE TO DETAIL SCREEN
}
});
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
tvDescription.setText(Html.fromHtml(calenderItem.getActivitie().getTitle(), Html.FROM_HTML_MODE_COMPACT));
} else {
tvDescription.setText(Html.fromHtml(calenderItem.getActivitie().getTitle()));
}
//HERE IS A PROBLEM WHEN SCROLLING
if(calenderItem.getCalType()== null || calenderItem.getCalType().equals("")){
tvSubDescription.setVisibility(View.GONE);
}else{
tvSubDescription.setText(calenderItem.getCalType());
}
//HERE IS ALSO A PROBLEM WHEN SCROLLING
if (calenderItem.getDate() != null){
tvDate.setText(calenderItem.getDate());
tvDate.setVisibility(View.VISIBLE);
}
//HERE EVERYTHING SEEMS OKE
Drawable background = ctx.getResources().getDrawable(R.drawable.circle);
switch (item.getType()){
case PROTHESE:
background.setColorFilter(ContextCompat.getColor(ctx, R.color.blue_grey_200), PorterDuff.Mode.SRC_IN);
ivIcon.setBackground(background);
break;
case NOTHING:
background.setColorFilter(ContextCompat.getColor(ctx, R.color.blue_grey_400), PorterDuff.Mode.SRC_IN);
ivIcon.setBackground(background);
break;
case DANGER:
background.setColorFilter(ContextCompat.getColor(ctx, R.color.blue_grey_800), PorterDuff.Mode.SRC_IN);
ivIcon.setBackground(background);
break;
}
}
public interface onInteractionListener {
public void moveToDetailFragment(CalenderItem calItem);
}
}
When I scroll, the tvDate is showed randomly in my list
where do I need to write this code to solve this problem?
Please try with below code.
//HERE IS ALSO A PROBLEM WHEN SCROLLING
if (calenderItem.getDate() != null){
tvDate.setText(calenderItem.getDate());
tvDate.setVisibility(View.VISIBLE);
}else {
tvDate.setVisibility(View.GONE);
}
Must be like that :
//HERE IS A PROBLEM WHEN SCROLLING
if(calenderItem.getCalType()== null || calenderItem.getCalType().equals("")){
tvSubDescription.setVisibility(View.GONE);
}else{
tvSubDescription.setText(calenderItem.getCalType());
tvSubDescription.setVisibility(View.VISIBLE);
}
//HERE IS ALSO A PROBLEM WHEN SCROLLING
if (calenderItem.getDate() != null){
tvDate.setText(calenderItem.getDate());
tvDate.setVisibility(View.VISIBLE);
} else {
tvDate.setVisibility(View.GONE);
}
Related
I have added simple v7.widget.RecyclerView and set the adapter simply but while scrolling the list it jerks allot, scrolling is not working out smoothly. Infact I used few library as well for fast scrolling but nothing works. I have picasso inside adapter to load images while data setting or handling visibility is done in "onBindViewHolder".
If someone have better solution than kindly help me out.
I already tried all the below methods but none of them works
#BindView(R.id.rv_list)
RecyclerView rvList;
ViewCompat.setNestedScrollingEnabled(rvList, false);
rvList.setNestedScrollingEnabled(false);
rvList.setHasFixedSize(true);
rvList.setItemViewCacheSize(20);
rvList.setDrawingCacheEnabled(true);
rvList.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
Below is my Adapter Code:
public class RecyclerAdapter extends RecyclerView.Adapter<cadapter.RecyclerAdapter.MyViewHolder> {
Context ctx;
ArrayList<Model> Modelslist;
GlobalClass gc;
View itemView;
View parentView;
private RecyclerAdapter.RecyclerAdapterListener listener;
PrefManager prefManager;
public RecyclerAdapter(Context context, ArrayList<Model> Modelslist, RecyclerAdapter.RecyclerAdapterListener listener) {
this.Modelslist = Modelslist;
this.ctx = context;
gc = GlobalClass.getInstance();
this.listener = listener;
prefManager = new PrefManager(context);
}
#Override
public int getItemViewType(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public RecyclerAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.layout, parent, false);
if (itemView == null) {
parentView = new RelativeLayout(this.ctx);
} else {
parentView = (RelativeLayout) itemView;
}
return new RecyclerAdapter.MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(final RecyclerAdapter.MyViewHolder holder, final int position) {
final Model cat = this.Modelslist.get(position);
holder.txtNumber.setText(cat.getNumber());
holder.txtName.setText(cat.getName());
final String flagPath = cat.getFlag();
if(cat.getForwarding1().equals("0")) {
holder.callForwardingSwitch.setChecked(true);
holder.txtCallRateVal.setText(cat.getForwardingCost());
holder.txtCallRateVal.setVisibility(View.VISIBLE);
holder.txtCallRate.setVisibility(View.VISIBLE);
holder.txtCallRateVal2.setVisibility(View.VISIBLE);
holder.txtCallRateVal2.setTextColor(ctx.getResources().getColor(R.color.text_grey));
////VISIBLE call Forwading Text
holder.txtCallRateVal.setVisibility(View.VISIBLE);
holder.txtCallRate.setVisibility(View.VISIBLE);
}else{
holder.callForwardingSwitch.setChecked(false);
////Hide call Forwading Text
holder.txtCallRateVal.setVisibility(View.INVISIBLE);
holder.txtCallRate.setVisibility(View.INVISIBLE);
holder.txtCallRateVal2.setVisibility(View.INVISIBLE);
}
holder.txtNumberDesc.setText(cat.getDetails());
holder.txtRenewDate.setText(cat.getrenewal_date());
holder.txtSetupVal.setText(cat.getcost());
holder.txtMonthlyVal.setText(cat.getmonthlycost());
String application_status= cat.getapplication_status();
System.out.println("Application status:::::: "+ application_status+" number: "+cat.getNumber());
if(application_status.equals("0")){
holder.txtStatus.setText("* Pending Approval");
holder.txtStatus.setVisibility(View.VISIBLE);
holder.txtStatus.setTextColor(ctx.getResources().getColor(R.color.account_error));
holder.txtCallRateVal.setVisibility(View.INVISIBLE);
holder.txtCallRateVal2.setVisibility(View.INVISIBLE);
holder.txtCallRate.setVisibility(View.INVISIBLE);
////////Unclicking Highlight Delete and call Forwarding
holder.Delete.setBackgroundResource(R.drawable.number_delete_gray);
holder.Delete.setClickable(false);
holder.callForwardingSwitch.setChecked(false);
holder.callForwardingSwitch.setClickable(false);
// holder.callForwardingSwitch.setHighlightColor(ctx.getResources().getColor(R.color.text_dark_grey));
/////////Visible Tag
holder.rel__number_status.setVisibility(View.VISIBLE);
holder.rel__number_status.setBackground(ctx.getDrawable(R.drawable._submitted_tag));
holder.txtNumberStatus.setText("Registration Submitted *");
/////// Hide Renew Date:
holder.txtRenew.setVisibility(View.GONE);
holder.txtRenewDate.setVisibility(View.GONE);
}else if(application_status.equals("1")){
holder.txtStatus.setText("Click here to complete number registration");
holder.txtStatus.setVisibility(View.VISIBLE);
/////////Visible Tag
holder.rel__number_status.setVisibility(View.VISIBLE);
holder.rel__number_status.setBackground(ctx.getDrawable(R.drawable._saved_tag));
holder.txtNumberStatus.setText("Registration Incomplete");
/////// Hide Renew Date:
holder.txtRenew.setVisibility(View.GONE);
holder.txtRenewDate.setVisibility(View.GONE);
holder.txtStatus.setTextColor(ctx.getResources().getColor(R.color.app_header));
}else if(application_status.equals("2")){//////Approved///
//holder.txtStatus.setText("Approved");
holder.txtStatus.setVisibility(View.VISIBLE);
holder.txtStatus.setText("Active");
holder.txtStatus.setTextColor(ctx.getResources().getColor(R.color.green600));
/////////Hide Tag
holder.rel__number_status.setVisibility(View.INVISIBLE);
holder.txtSetupVal.setVisibility(View.GONE);
holder.txtSetup.setVisibility(View.GONE);
/////// VISIBLE Renew Date:
holder.txtRenew.setVisibility(View.VISIBLE);
holder.txtRenewDate.setVisibility(View.VISIBLE);
}else if(application_status.equals("3")){///// Rejected///
//holder.txtStatus.setText("Rejected");
/////////Hide Tag
holder.txtStatus.setVisibility(View.INVISIBLE);
holder.rel__number_status.setVisibility(View.INVISIBLE);
/////// VISIBLE Renew Date:
holder.txtRenew.setVisibility(View.VISIBLE);
holder.txtRenewDate.setVisibility(View.VISIBLE);
}else{
if(cat.getLocal().equals("1") && cat.getAddress().equals("1")
&& cat.getPhoto().equals("1") && cat.getapplication_status().equals("-1")){
holder.txtStatus.setVisibility(View.VISIBLE);
holder.txtStatus.setText("Active");
holder.txtStatus.setTextColor(ctx.getResources().getColor(R.color.green600));
holder.rel__number_status.setVisibility(View.INVISIBLE);
holder.txtSetupVal.setVisibility(View.GONE);
holder.txtSetup.setVisibility(View.GONE);
}else{
holder.txtStatus.setText("");
/////////Hide Tag
holder.txtStatus.setVisibility(View.INVISIBLE);
holder.rel__number_status.setVisibility(View.INVISIBLE);
}
}
System.out.println("Flag::::::::::: "+ flagPath);
/*Picasso.with(ctx)
.load(flagPath) // thumbnail url goes here
.into(holder.CountryFlagim, new Callback() {
#Override
public void onSuccess() {
Picasso.with(ctx)
.load(flagPath) // image url goes here
.placeholder(holder.CountryFlagim.getDrawable())
.into(holder.CountryFlagim);
}
#Override
public void onError() {
}
});*/
Glide
.with(ctx)
.load(flagPath)
.centerCrop()
.placeholder(holder.CountryFlagim.getDrawable())
.into(holder.CountryFlagim);
//Picasso.with(ctx).load(flagPath).into(holder.CountryFlagim);
applyClickEvents(holder,position);
}
#Override
public int getItemCount() {
if (this.Modelslist != null) {
return this.Modelslist.size();
} else {
return 0;
}
}
private void applyClickEvents(final RecyclerAdapter.MyViewHolder holder, final int position) {
holder.mainFrame.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
listener.moveToDetailScreen(position);
}
});
holder.Delete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
final Model cat = Modelslist.get(position);
}
});
holder.callForwardingSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
System.out.println("Call forwarding switch: "+ b);
}
});
}
public interface NumberListAdapterListener {
void deleteItem(int position);
void moveToDetailScreen(int position);
}
public class MyViewHolder extends RecyclerView.ViewHolder {
RelativeLayout rel__number,rel__setup,rel__number_status;
ImageView CountryFlagim;
TextView txtNumber, txtName;
SwitchCompat callForwardingSwitch;
TextView txtNumberDesc;
TextView txtSetupVal, txtSetup;
TextView txtMonthlyVal;
TextView txtCallRateVal, txtCallRateVal2, txtCallRate;
TextView txtStatus;
TextView txtNumberStatus, txtRenewDate, txtRenew;
Button Delete;
RelativeLayout mainFrame;
public MyViewHolder(View v) {
super(v);
rel__number = (RelativeLayout) v.findViewById(R.id.rel__number);
rel__setup = (RelativeLayout) v.findViewById(R.id.rel__setup);
rel__number_status = (RelativeLayout) v.findViewById(R.id.rel__number_status);
CountryFlagim = (ImageView) v.findViewById(R.id.CountryFlagim);
txtNumber = (TextView) v.findViewById(R.id.txtNumber);
txtName = (TextView) v.findViewById(R.id.txtName);
txtNumberDesc = (TextView) v.findViewById(R.id.txtNumberDesc);
txtSetupVal = (TextView) v.findViewById(R.id.txtSetupVal);
txtSetup = (TextView) v.findViewById(R.id.txtSetup);
txtMonthlyVal = (TextView) v.findViewById(R.id.txtMonthlyVal);
txtCallRate = (TextView) v.findViewById(R.id.txtCallRate);
txtCallRateVal = (TextView) v.findViewById(R.id.txtCallRateVal);
txtCallRateVal2 = (TextView) v.findViewById(R.id.txtCallRateVal2) ;
txtStatus = (TextView) v.findViewById(R.id.txtStatus);
txtNumberStatus = (TextView) v.findViewById(R.id.txtNumberStatus);
Delete = (Button) v.findViewById(R.id.Delete);
callForwardingSwitch = (SwitchCompat) v.findViewById(R.id.callForwardingSwitch);
mainFrame = (RelativeLayout) v.findViewById(R.id.mainFrame);
txtRenewDate = (TextView) v.findViewById(R.id.txtRenewDate);
txtRenew = (TextView) v.findViewById(R.id.txtRenew);
}
}
}
You can try Glide. Glide doesn't load full size picture and uses less memory, which should be faster than Picasso.
I have two tabs (fragments), NewOrders and FinishedOrders, I'm populating the orders via Volley requests, now each item inside the New Orders tab has a SwipeLayout which show a clickable textview that makes the order finished, and move it to the other tab (backend stuff..), and I got this working perfectly,
The problem is when I click to finish, the recyclerview isn't updated once the request sent successfully, I have to do pull-to-refresh so it would update..! it seems easy to solve, but the issue is handling the swipelayout listener done inside onBindView method inside the adapter..!! that's only place to access it according to the library I'm using (I guess)..! on the other hand refreshing and populating the list happens in the NewOrder tab fragment..!
So how can I make the item to be removed from the list after the click and becomes updated..?!
Any thoughts..!?
My Adapter Class + ViewHolder
Note: the implemented methods in the adapter are required because of the interface of SwipeLayout library
public class OrdersDataAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
implements SwipeAdapterInterface, SwipeItemMangerInterface {
protected SwipeItemRecyclerMangerImpl mItemManger = new SwipeItemRecyclerMangerImpl(this);
public Context context;
ArrayList<OrderPresenter> orders;
public OrdersDataAdapter(ArrayList<OrderPresenter> orders, Context context) {
this.orders = orders;
this.context = context;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.order_card, parent, false);
return new NewOrderVH(v);
}
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
final OrderPresenter order = this.orders.get(position);
final NewOrderVH vh1 = (NewOrderVH) holder;
vh1.setData(orders.get(position));
mItemManger.bindView(vh1.itemView, position);
vh1.swipeLayout.setShowMode(SwipeLayout.ShowMode.PullOut);
vh1.swipeLayout.addDrag(SwipeLayout.DragEdge.Left,
vh1.swipeLayout.findViewById(R.id.bottom_wrapper));
if (order.isFinished()) {
vh1.swipeLayout.setSwipeEnabled(false);
vh1.setBadge("DONE");
vh1.setBadgeColor(order.getBadgeColor());
} else {
vh1.finish.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// get the clicked item position?
final int position = vh1.getAdapterPosition();
// these responsible for the request which make the order finished
OrderPresenter order = orders.get(position);
OrderRepository.setOrderFinURL(order.getID());
OrderRepository.FinishOrder(order.getID(), context);
/*the commented three lines below didn't help with the problem*/
// notifyItemChanged(position);
// notifyItemRemoved(position);
// notifyDataSetChanged();*/
order.setStatus(order.getStatusText(Order.FINISHED));
}
});
}
}
#Override
public int getItemCount() {
return orders.size();
}
public class NewOrderVH extends RecyclerView.ViewHolder {
SwipeLayout swipeLayout;
private TextView finish;
private CardView orderCard;
TextView Badge;
private ImageView cusPic;
private TextView cusName;
private TextView CusAdress;
private TextView vendorsNum;
private TextView itemsNum;
private TextView time;
private TextView emptyView;
public NewOrderVH(View itemView) {
super(itemView);
Badge = (TextView) itemView.findViewById(R.id.badge);
swipeLayout = (SwipeLayout) itemView.findViewById(R.id.swipe);
finish = (TextView) itemView.findViewById(R.id.finish);
orderCard = (CardView) itemView.findViewById(R.id.OrderCard);
cusPic = (ImageView) itemView.findViewById(R.id.cusPic);
cusName = (TextView) itemView.findViewById(R.id.cusName);
CusAdress = (TextView) itemView.findViewById(R.id.CusAdress);
vendorsNum = (TextView) itemView.findViewById(R.id.vendorsNum);
itemsNum = (TextView) itemView.findViewById(R.id.itemsNum);
time = (TextView) itemView.findViewById(R.id.time);
emptyView = (TextView) itemView.findViewById(R.id.empty_view);
orderCard.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(v.getContext(), OrderDetails.class);
v.getContext().startActivity(intent);
}
});
}
public void setData(final OrderPresenter data) {
time.setText(data.getOrderTime());
cusName.setText(data.getFullName());
vendorsNum.setText(data.getVendorsCount());
itemsNum.setText(data.getItemsCount());
CusAdress.setText(data.getFullAddress());
Picasso.with(context).load(data.getCustomerPicture()).into(cusPic);
}
public void setBadgeColor(int drawable) {
this.Badge.setBackgroundResource(drawable);
}
public void setBadge(String badge) {
this.Badge.setText(badge);
}
}
#Override
public int getSwipeLayoutResourceId(int position) {
return R.id.swipe;
}
#Override
public void openItem(int position) {
}
#Override
public void closeItem(int position) {
}
#Override
public void closeAllExcept(SwipeLayout layout) {
}
#Override
public void closeAllItems() {
}
#Override
public List<Integer> getOpenItems() {
return null;
}
#Override
public List<SwipeLayout> getOpenLayouts() {
return null;
}
#Override
public void removeShownLayouts(SwipeLayout layout) {
}
#Override
public boolean isOpen(int position) {
return false;
}
#Override
public Attributes.Mode getMode() {
return null;
}
#Override
public void setMode(Attributes.Mode mode) {
}
}
My NewOrder Fragment
Note: the FinishedOrders tab (fragment) does the same thing as new order but filters the current the Finished status.
public class NewOrdersTab extends Fragment {
RecyclerView recyclerView;
OrdersDataAdapter adapter;
private SwipeRefreshLayout swiperefresh;
private TextView emptyView;
ArrayList<OrderPresenter> modelData;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View rootView = inflater.inflate(R.layout.new_orders_tab_frag, container, false);
modelData = new ArrayList<>();
recyclerView = (RecyclerView) rootView.findViewById(R.id.recyclerView);
swiperefresh = (SwipeRefreshLayout) rootView.findViewById(R.id.swiperefresh);
recyclerView.setLayoutManager(new LinearLayoutManager(this.getActivity()));
swiperefresh.setColorSchemeResources(R.color.colorPrimary, R.color.color_error, R.color.colorInfo);
adapter = new OrdersDataAdapter(modelData, getActivity());
emptyView = (TextView) rootView.findViewById(R.id.empty_view);
recyclerView.setAdapter(adapter);
adapter.setMode(Attributes.Mode.Single);
OrderRepository.fetchOrders("awaiting-shipment", getActivity(), new DataFetch() {
#Override
public void onResponse(ArrayList<OrderPresenter> data) {
swiperefresh.setRefreshing(true);
if (data.size() != 0) {
swiperefresh.setRefreshing(true);
emptyView.setVisibility(View.GONE);
modelData.clear();
modelData.addAll(data);
adapter.notifyDataSetChanged();
} else {
emptyView.setVisibility(View.VISIBLE);
emptyView.setText(getString(R.string.No_New_Orders));
}
swiperefresh.setRefreshing(false);
}
});
return rootView;
}
}
I figured it out, I just added these two lines after I make the request..!
orders.remove(position);
notifyItemRemoved(position);
//notifyDataSetChanged(position);
I have a recycler view, which consists of list. The items in the list have their own details like this (each item will have image, id, name, description), and the items are shuffeled, not in order.
Example : recyclerview item position = 0, list item id= 7.
recyclerview item position = 1, list item id= 5.
recyclerview item position = 2, list item id= 12.
So i need to get the list item id on recycler on click. If i click on recyclerview position = 0, If i have to get the item id as 7. So that i can work on that furthur based on that id.
My example code is
recommendedrecyclerView=(RecyclerView)view.findViewById(R.id.recommended_recycler_view);
recommendedrecyclerView.setNestedScrollingEnabled(false);
recommendedrecyclerView.setLayoutManager(new LinearLayoutManager(getActivity(),OrientationHelper.VERTICAL,true));
recommendedrecyclerView.setItemAnimator(new DefaultItemAnimator());
I am getting data from server and setting it to adapter
setrecommendedAppsContent(response.body().getData());
public void setrecommendedAppsContent(List<FeaturedAppsData> data){
if (data!=null&&data.size()>0) {
recommendedAdapter = new RecommendedAdapter(mCurrentContext, data);
recommendedrecyclerView.setAdapter(recommendedAdapter);
recommendedAdapter.setClickListener(this);
}
}
This is my adapter class
public class RecommendedAdapter extends RecyclerView.Adapter<RecommendedAdapter.ItemViewHolder> {
private LayoutInflater inflater = null;
private Context context;
private List<FeaturedAppsData> itemsData;
private ClickListener clicklistener = null;
public TextView recommendedAppTitle,recommendedAppCategory,recommendedAppDescription;
public ImageView recommendedAppIcon;
Button recommendedBtn;
String appId;
public void setClickListener(ClickListener clickListener) {
this.clicklistener = clickListener;
}
public RecommendedAdapter(Context context, List<FeaturedAppsData> itemsData) {
this.context = context;
this.itemsData = itemsData;
}
#Override
public void onBindViewHolder(ItemViewHolder holder, int position) {
holder.recommendedAppTitle.setText(itemsData.get(position).getName());
holder.recommendedAppCategory.setText(itemsData.get(position).getApp_description());
holder.recommendedAppDescription.setText(itemsData.get(position).getOffer_description());
holder.recommendedAppBtn.setText(itemsData.get(position).getButton_text());
String imageUrl = String.valueOf(itemsData.get(position).getImage().getUrl());
Glide.with(context).load(ApiConstant.ApiBaseUrl + imageUrl).into(recommendedAppIcon);
appId=itemsData.get(position).getId();
}
#Override
public int getItemCount() {
int size = 0;
if (itemsData != null && itemsData.size() > 0) {
size = itemsData.size();
}
return size;
}
public class ItemViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public TextView recommendedAppTitle,recommendedAppCategory,recommendedAppDescription,offerDescription,offerDetailDescription,rewardDetail;
public ImageView recommendedAppIcon;
public Button recommendedAppBtn;
public ArrayList<FeaturedAppsData> dataItems;
private Context context;
public ItemViewHolder(Context context, View itemView, int viewType) {
super(itemView);
this.context = context;
itemView.setOnClickListener(this);
recommendedAppTitle = (TextView) itemView.findViewById(R.id.recommended_app_title);
recommendedAppCategory = (TextView) itemView.findViewById(R.id.recommended_app_category);
recommendedAppDescription = (TextView) itemView.findViewById(R.id.recommended_app_description);
recommendedAppIcon = (ImageView) itemView.findViewById(R.id.recommended_app_icon);
recommendedAppBtn=(Button)itemView.findViewById(R.id.recommended_app_card_btn);
}
#Override
public void onClick(View v) {
if (clicklistener != null) {
clicklistener.itemClicked(v, getAdapterPosition());
}
}
}
#Override
public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = null;
inflater = LayoutInflater.from(context);
view = inflater.inflate(R.layout.recommended_item_layout, parent, false);
recommendedAppIcon=(ImageView)view.findViewById(R.id.recommended_app_icon);
return new ItemViewHolder(context, view, viewType);
}
}
I am not sure of the Onclick method. So please suggest me as required along with Onclick event.
The setOnClickListener inside the ViewHolder is a good way.
Considering your current solution, the easiest way is to change the ClickListener interface, put the data inside the Holder during onBindViewHolder and then pass it to the listener during onClick. Like this:
Change the view holder fields to:
public class ItemViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public TextView recommendedAppTitle,recommendedAppCategory,recommendedAppDescription,offerDescription,offerDetailDescription,rewardDetail;
public ImageView recommendedAppIcon;
public Button recommendedAppBtn;
public FeaturedAppsData data; // <<< ADD THIS
// remove that u don't need public ArrayList<FeaturedAppsData> dataItems;
// remove that u don't need private Context context;
... the rest of your holder
then inside onBindViewHolder
#Override
public void onBindViewHolder(ItemViewHolder holder, int position) {
holder.data = itemsData.get(position);
... the rest on bind
then inside onClick, inside the holder:
#Override
public void onClick(View v) {
if (clicklistener != null) {
clicklistener.itemClicked(v, data.getId());
}
}
I've added a NativeExpressAdView inside my RecyclerView ItemList but now the onClickListener is interfering with the NativeExpressAdView. My "normal" Items consist of text and one larger Image. When the larger Image gets clicked on, a DialogFragment gets opened and shows detailed information of the Item. However, the NativeExpressAdView shouldn't run into this onClickListener. The App keeps crashing because it tries to open the not existing detailed View of the NativeExpressAdView ...
MainActivity
...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
......
recyclerView.addOnItemTouchListener(new ItemAdapter.RecyclerTouchListener(getApplicationContext(), recyclerView, new ItemAdapter.ClickListener() {
#Override
public void onClick(View view, final int position) {
final Bundle bundle = new Bundle();
bundle.putSerializable("events", events);
bundle.putInt("position", position);
final Event event = events.get(position);
detailView = (ImageView) view.findViewById(R.id.item_thumbnail);
detailView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
android.support.v4.app.FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
SlideshowDialogFragment newFragment = SlideshowDialogFragment.newInstance();
newFragment.setArguments(bundle);
newFragment.setCancelable(true);
newFragment.show(ft, "slideshow");
}
});
....
some other button onClickListener()...
....
}
#Override
public void onLongClick(View view, int position) {
}
}));
ItemAdapter
public class ItemAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
private List<Event> events;
private Context mContext;
public ItemAdapter(Context context, List<Event> events){
mContext = context;
this.events = events;
}
public static class MyViewHolder extends RecyclerView.ViewHolder{ // implements View.OnClickListener {
public ImageView thumbnail;
public TextView event_name;
public TextView event_date;
public TextView event_descr;
public TextView event_attending;
public TextView event_maybe;
public MyViewHolder(android.view.View view){
super(view);
thumbnail = (ImageView) view.findViewById(R.id.item_thumbnail);
event_name = (TextView) view.findViewById(R.id.tV_event_name);
event_date = (TextView) view.findViewById(R.id.tV_event_date);
event_descr = (TextView) view.findViewById(R.id.tV_event_descr);
event_attending = (TextView) view.findViewById(R.id.tV_attending_count);
event_maybe = (TextView) view.findViewById(R.id.tV_maybe_count);
}
}
public static class ViewHolderAdMob extends RecyclerView.ViewHolder {
public NativeExpressAdView nativeExpressAdView;
public ViewHolderAdMob(View view) {
super(view);
nativeExpressAdView = (NativeExpressAdView) view.findViewById(R.id.ad_nativeAdOne);
AdRequest adRequest = new AdRequest.Builder()
.addTestDevice(AdRequest.DEVICE_ID_EMULATOR)
.addTestDevice("228****************************")
.build();
nativeExpressAdView.loadAd(adRequest);
}
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType){
RecyclerView.ViewHolder viewHolder = null;
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
//View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.rv_items, parent, false);
switch (viewType){
case 1:{
View itemView = inflater.inflate(R.layout.rv_items, parent, false);
viewHolder = new MyViewHolder(itemView);
break;
}
case 2:{
View itemView = inflater.inflate(R.layout.native_ad_one, parent, false);
viewHolder = new ViewHolderAdMob(itemView);
break;
}
}
return viewHolder;
}
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position){
Event event = events.get(position);
switch (holder.getItemViewType()){
case 1:{
MyViewHolder viewHolder = (MyViewHolder) holder;
viewHolder.event_name.setText(event.getEventName());
viewHolder.event_date.setText(event.getEventDate());
viewHolder.event_descr.setText(event.getEventDescription());
viewHolder.event_attending.setText(event.getEventAttending());
viewHolder.event_maybe.setText(event.getEventMaybeComming());
Glide.with(mContext).load(event.getEventImage())
.thumbnail(0.9f)
.crossFade()
//.diskCacheStrategy(DiskCacheStrategy.ALL)
.fitCenter()
.into(viewHolder.thumbnail);
break;
}
case 2:{
break;
}
}
}
#Override
public int getItemCount(){
return events.size();
}
#Override
public int getItemViewType(int position) {
return events.get(position).getViewType();
}
public interface ClickListener {
void onClick(View view, int position);
void onLongClick(View view, int position);
}
public static class RecyclerTouchListener implements RecyclerView.OnItemTouchListener {
private GestureDetector gestureDetector;
private ItemAdapter.ClickListener clickListener;
public RecyclerTouchListener(final Context context, final RecyclerView recyclerView, final ItemAdapter.ClickListener clickListener){
this.clickListener = clickListener;
gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener(){
#Override
public boolean onSingleTapUp(MotionEvent e){
return true;
}
#Override
public void onLongPress(MotionEvent e) {
View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
if (child != null && clickListener != null) {
clickListener.onLongClick(child, recyclerView.getChildPosition(child));
}
}
});
}
#Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e){
View child = rv.findChildViewUnder(e.getX(), e.getY());
if (child != null && clickListener != null && gestureDetector.onTouchEvent(e)){
clickListener.onClick(child, rv.getChildPosition(child));
}
return false;
}
#Override
public void onTouchEvent(RecyclerView rv, MotionEvent e){
}
#Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept){
}
}
}
I kind of see where the problem stems from, since the the RecyclerView is listening for input and naturally reacts to it but I kind of thought that by defining inside my MainActivity that detailView = (ImageView) view.findViewById(R.id.item_thumbnail); it will only react to "normal" items since R.id.item_thumbnail is an element of my "normal" items xml whereas the NativeExpressAdView doesn't have such an element. How can I fix this problem and get the proper functionality ??
Set the click listener in onBindViewHolder, in your adapter, depending on the view type.
public static class ItemAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final MyListClickListener clickListener;
public ItemAdapter(MyListClickListener clickListener) {
this.clickListener = clickListener;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (getItemViewType(position) == ADVERT_VIEW_TYPE) {
// do whatever you do for adverts
} else {
// do what you do for items and set the click listener
holder.itemView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
clickListener.onShowDetailViewClicked(); // pass the parameters you need to identify this particular item
}
});
}
}
public interface MyListClickListener {
void onShowDetailViewClicked();
}
}
You are setting the onItemTouchListener{...} to the entire RecyclerView. It assumes that no matter where you touch, there is the detail view. But you have different types of rows in your RecyclerView. The best option would be to add touch listeners to each individual item in your ViewHolder classes.
I'm using RecyclerView for a long list and when i scroll too fast, something weird happens. There are two problems.
First one is the one in the image below. One of items (like red bordered one in the image) sticks on some random part of the screen and blocks other items. It disappears when the real version of that item becomes visible on the screen.
Another problem about scrolling this long RecyclerView too fast is sticking onClick effect. Some of items become visible like someone is pressing on them.
Are these problems about my adapter or are they common problems about RecyclerView? Here is my adapter:
public class SimpleListItemRecyclerAdapter extends RecyclerView.Adapter<SimpleListItemRecyclerAdapter.ListItemViewHolder> {
Context context;
ArrayList<RecyclerItemModel> list;
OnRecyclerViewItemClickListener onRecyclerViewItemClickListener;
private int lastPosition = -1;
private boolean isClickable;
public SimpleListItemRecyclerAdapter(ArrayList<RecyclerItemModel> list, _FragmentTemplate fragment) {
this.list = list;
this.context = fragment.getActivity();
try {
this.onRecyclerViewItemClickListener = (OnRecyclerViewItemClickListener) fragment;
isClickable = true;
} catch (ClassCastException e) {
isClickable = false;
}
setHasStableIds(true);
}
#Override
public ListItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).
inflate(R.layout.item_sub_main_list_single_text,
parent,
false);
return new ListItemViewHolder(itemView, onRecyclerViewItemClickListener, isClickable, list.get(0).getHeight());
}
#Override
public void onBindViewHolder(ListItemViewHolder holder, int position) {
final RecyclerItemModel recyclerItem = list.get(position);
if (recyclerItem.isBackgroundColorSpecified())
holder.itemView.setBackgroundResource(recyclerItem.getBackgroundColorResource());
else {
final int[] backgroundColors = Preferences.backgroundSelectorsGrey;
holder.itemView.setBackgroundResource(backgroundColors[position % backgroundColors.length]);
}
holder.textMain.setText(recyclerItem.getTextMain());
if (recyclerItem.isImageRightAvailable()) {
if (recyclerItem.isProgressBarAvailable())
if (recyclerItem.shouldShowDoneImage())
setDrawableFromSVG(holder.imageRight, recyclerItem.getImageRightResourceDone());
else
setDrawableFromSVG(holder.imageRight, recyclerItem.getImageRightResource());
} else
holder.imageRight.setVisibility(View.GONE);
if (recyclerItem.isTextMainBottomAvailable())
holder.textMainBottom.setText(recyclerItem.getTextMainBottom());
else
holder.textMainBottom.setVisibility(View.GONE);
if (recyclerItem.isTextRightTopAvailable())
holder.textRightTop.setText(recyclerItem.getTextRightTop());
else
holder.textRightTop.setVisibility(View.GONE);
if (recyclerItem.isTextRightBottomAvailable())
holder.textRightBottom.setText(recyclerItem.getTextRightBottom());
else
holder.textRightBottom.setVisibility(View.GONE);
if (recyclerItem.isProgressBarAvailable())
holder.progressBar.setProgress(recyclerItem.getProgress());
else
holder.progressBar.setVisibility(View.GONE);
setAnimation(holder.itemView, position);
}
#Override
public long getItemId(int position) {
return list.get(position).hashCode();
}
#Override
public int getItemCount() {
return list.size();
}
private void setAnimation(View viewToAnimate, int position) {
if (position > lastPosition) {
Animation animation = AnimationUtils.loadAnimation(context, R.anim.appear);
viewToAnimate.startAnimation(animation);
lastPosition = position;
}
}
public Drawable setDrawableFromSVG(ImageView imageView, int resource) {
SVG svg = new SVGBuilder()
.readFromResource(context.getResources(), resource)
.build();
imageView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
imageView.setImageDrawable(svg.getDrawable());
return svg.getDrawable();
}
public final static class ListItemViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
OnRecyclerViewItemClickListener onRecyclerViewItemClickListener;
TextView textMain, textMainBottom, textRightTop, textRightBottom;
ImageView imageRight;
ProgressBar progressBar;
View itemView;
public ListItemViewHolder(View itemView, OnRecyclerViewItemClickListener onRecyclerViewItemClickListener,
boolean isClickable, int height) {
super(itemView);
this.itemView = itemView;
this.onRecyclerViewItemClickListener = onRecyclerViewItemClickListener;
textMain = (TextView) itemView.findViewById(R.id.list_item_text_main);
imageRight = (ImageView) itemView.findViewById(R.id.list_item_image_right);
textRightTop = (TextView) itemView.findViewById(R.id.list_item_text_right_top);
textRightBottom = (TextView) itemView.findViewById(R.id.list_item_text_right_bottom);
textMainBottom = (TextView) itemView.findViewById(R.id.list_item_text_main_bottom);
progressBar = (ProgressBar) itemView.findViewById(R.id.list_item_progress_bar);
switch (height) {
case RecyclerItemModel.HEIGHT_FULL:
itemView.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, Preferences.squareLength));
break;
case RecyclerItemModel.HEIGHT_HALF:
itemView.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, Preferences.squareLength / 2));
}
if (isClickable)
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
onRecyclerViewItemClickListener.onRecyclerViewItemClick(getPosition());
}
}
}
Here is what resolved my problem:
Animating somehow causes a problem on RecyclerView. So the solution for me was removing the following line:
setAnimation(holder.itemView, position);
I didn't try to add animation again but if you really need it, here is something that can be useful: How to animate RecyclerView items when they appear.