I have two nested RecyclerViews - basically a list of horizontal RecyclerViews and I am struggling to make the items in the horizontal RecyclerView clickable.
This is the main layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/overview_list"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<components.emptyView.EmptyView
android:id="#+id/empty_state"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"/>
</LinearLayout>
Then RecyclerView has the following item layout:
<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView android:id="#+id/tables"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp"
android:clipToPadding="false"
android:paddingEnd="18dp"
android:paddingStart="18dp"/>
And I'm trying to get the onclick setup in the adapter for the inner RecyclerView as follows:
#Override
public void onBindViewHolder(#NonNull LeagueTableViewHolder holder, int position) {
Pair<Long, String> table = tables.get(position);
holder.bindTable(table.first, table.second);
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// click event here
}
});
}
I've tried making the ViewHolder's itemview as clickable programatically and in XML and it doesn't seem to make a difference. Same for the inner RecyclerView.
Any idea what I'm doing wrong?
Edit: Added parent RecyclerView adapter
public class OverviewListAdapter extends RecyclerView.Adapter<BaseViewHolder> {
public final static int TEAM_PICTURE = 0;
public final static int FIXTURES = 1;
public final static int LEAGUE_TABLES = 2;
public final static int LATEST_NEWS = 3;
public final static int LATEST_EVENTS = 4;
private final RecyclerView.RecycledViewPool viewPool;
private List<BaseOverviewItemVM> viewModels = new ArrayList<>();
private int tint;
private OverviewLatestNewsVM newsVM;
private OverviewLatestEventsVM eventsVM;
private OverviewTablesVM tablesVM;
private OverviewFixturesVM fixturesVM;
private OverviewTeamPicVM teamPicVM;
OverviewListAdapter(int tint) {
this.tint = tint;
viewPool = new RecyclerView.RecycledViewPool();
}
void addViewModel(OverviewLatestNewsVM viewModel){
if(newsVM == null){
newsVM = viewModel;
viewModels.add(newsVM);
sort();
int viewModelIndex = viewModels.indexOf(newsVM);
notifyItemInsertedIfValid(viewModelIndex);
} else {
int currentNewsIndex = viewModels.indexOf(newsVM);
newsVM = viewModel;
if(currentNewsIndex >= 0) {
this.viewModels.set(currentNewsIndex, newsVM);
}
notifyItemChangedIfValid(currentNewsIndex);
}
}
void addViewModel(OverviewLatestEventsVM viewModel){
if(eventsVM == null){
eventsVM = viewModel;
viewModels.add(eventsVM);
sort();
int viewModelIndex = viewModels.indexOf(eventsVM);
notifyItemChangedIfValid(viewModelIndex);
} else {
int currentIndex = viewModels.indexOf(eventsVM);
eventsVM = viewModel;
if(currentIndex >= 0) {
this.viewModels.set(currentIndex, eventsVM);
}
notifyItemChangedIfValid(currentIndex);
}
}
void addViewModel(OverviewFixturesVM viewModel){
if(fixturesVM == null){
fixturesVM = viewModel;
viewModels.add(fixturesVM);
sort();
int viewModelIndex = viewModels.indexOf(fixturesVM);
notifyItemChangedIfValid(viewModelIndex);
} else {
int currentIndex = viewModels.indexOf(fixturesVM);
fixturesVM = viewModel;
if(currentIndex >= 0) {
this.viewModels.set(currentIndex, fixturesVM);
}
notifyItemChangedIfValid(currentIndex);
}
}
void addViewModel(OverviewTablesVM viewModel){
if(tablesVM == null){
tablesVM = viewModel;
viewModels.add(tablesVM);
sort();
int viewModelIndex = viewModels.indexOf(tablesVM);
notifyItemChangedIfValid(viewModelIndex);
} else {
int currentIndex = viewModels.indexOf(tablesVM);
tablesVM = viewModel;
if(currentIndex >= 0) {
this.viewModels.set(currentIndex, tablesVM);
}
notifyItemChangedIfValid(currentIndex);
}
}
void addViewModel(OverviewTeamPicVM viewModel){
if(teamPicVM == null){
teamPicVM = viewModel;
viewModels.add(teamPicVM);
sort();
int viewModelIndex = viewModels.indexOf(teamPicVM);
notifyItemChangedIfValid(viewModelIndex);
} else {
int currentIndex = viewModels.indexOf(teamPicVM);
teamPicVM = viewModel;
if(currentIndex >= 0) {
this.viewModels.set(currentIndex, teamPicVM);
}
notifyItemChangedIfValid(currentIndex);
}
}
private void sort(){
// sort by the item type defined at the top of this class
Collections.sort(viewModels, (o1, o2) -> {
if(o1.getType() > o2.getType()){
return 1;
} else if(o1.getType() < o2.getType()){
return -1;
}
return 0;
});
}
private void notifyItemInsertedIfValid(int index){
if(index >= 0 && index < getItemCount()){
notifyItemInserted(index);
} else {
notifyDataSetChanged();
}
}
private void notifyItemChangedIfValid(int index){
if(index >= 0 && index < getItemCount()){
notifyItemChanged(index);
} else {
notifyDataSetChanged();
}
}
#NonNull
#Override
public BaseViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
switch (viewType){
case FIXTURES:
View fixturesView = inflater.inflate(R.layout.row_overview_fixtures, parent, false);
OverviewFixturesVH fixturesHolder = new OverviewFixturesVH(fixturesView);
fixturesHolder.fixturesOverview.setRecycledViewPool(viewPool);
return fixturesHolder;
case LEAGUE_TABLES:
View tablesView = inflater.inflate(R.layout.row_overview_league_tables, parent, false);
OverviewTablesVH tablesHolder = new OverviewTablesVH(tablesView);
tablesHolder.tablesList.setRecycledViewPool(viewPool);
return tablesHolder;
case LATEST_EVENTS:
View upcomingEvents = inflater.inflate(R.layout.row_latest_list_view, parent, false);
return new OverviewLatestEventsVH(upcomingEvents, tint);
case TEAM_PICTURE:
View teamPicView = inflater.inflate(R.layout.row_overview_team_pic, parent, false);
return new OverviewTeamPicVH(teamPicView);
default:
View latestNewsView = inflater.inflate(R.layout.row_latest_list_view, parent, false);
return new OverviewLatestNewsVH(latestNewsView, tint);
}
}
#Override
public void onBindViewHolder(#NonNull BaseViewHolder holder, int position) {
if(holder instanceof OverviewFixturesVH) {
Optional<BaseOverviewItemVM> fixturesVM = getViewModelOfType(FIXTURES);
fixturesVM.ifPresent(viewModel -> ((OverviewFixturesVH) holder).setFixtures(((OverviewFixturesVM)viewModel).getFixtures()));
} else if (holder instanceof OverviewTablesVH) {
Optional<BaseOverviewItemVM> tablesVM = getViewModelOfType(LEAGUE_TABLES);
tablesVM.ifPresent(vm -> ((OverviewTablesVH) holder).setTableIds(((OverviewTablesVM) vm).getTableIds()));
} else if (holder instanceof OverviewLatestEventsVH){
Optional<BaseOverviewItemVM> eventsVM = getViewModelOfType(LATEST_EVENTS);
eventsVM.ifPresent(vm -> ((OverviewLatestEventsVH) holder).setEvents(((OverviewLatestEventsVM) vm).getEvents()));
} else if (holder instanceof OverviewLatestNewsVH){
Optional<BaseOverviewItemVM> newsVM = getViewModelOfType(LATEST_NEWS);
newsVM.ifPresent(vm -> ((OverviewLatestNewsVH) holder).setNews(((OverviewLatestNewsVM) vm).getNews()));
} else if (holder instanceof OverviewTeamPicVH){
Optional<BaseOverviewItemVM> teamPicVM = getViewModelOfType(TEAM_PICTURE);
teamPicVM.ifPresent(vm -> ((OverviewTeamPicVH) holder).setPictureUrl(((OverviewTeamPicVM) vm).getTeamPicUrl()));
}
}
#Override
public int getItemViewType(int position) {
return viewModels.get(position).getType();
}
#Override
public int getItemCount() {
return viewModels.size();
}
private Optional<BaseOverviewItemVM> getViewModelOfType(int type){
if(viewModels != null ) {
for (BaseOverviewItemVM viewModel : viewModels) {
if(viewModel.getType() == type){
return Optional.of(viewModel);
}
}
}
return Optional.empty();
}
}
I think you will be able to handle it creating a listener and handle the call with it:
public interface clickListenerItem {
void onItemClick(Item element);
}
add this interface in your adapter and in your main.
Adding this function to your *nameclass*ViewHolder extends RecyclerView.ViewHolder :
public void bind(final ItemName item, final clickListenerItem listener) {
itemView.setOnClickListener(new View.OnClickListener() {
#Override public void onClick(View v) {
listener.onItemClick(item);
}
});
}
then add to your Adapter variables: private final clickListenerItem clickItem;
in your constructor: this.clickItem = clickItem;
and in onBindViewHolder of your adapter call:
public void onBindViewHolder(final #NonNull ItemViewHolder holder, int position) {
holder.bind(list.get(position), clickItem);
}
now when initiliazing your adapter in the main you just add your listener adding it with a call like this:
adapter = new ItemAdapter(this, list, (new ItemAdapter.clickListenerItem(){
#Override public void onItemClick(Item thisItem) {
Toast.makeText(getApplicationContext(), "Loading Item...", Toast.LENGTH_LONG).show();
Intent viewElem = new Intent(getApplicationContext(), ViewItem.class);
startActivityForResult(viewElem ,codeForResult);
}
}));
I hope this will help you, obviusly you can change the last part for not calling a new activity but changing it with what you want to see or do with your item.
Related
So, basically what I am trying to do is to show a bunch of Post type objects on my Android app's feed (HomeFragment). The posts are being successfully retrieved from Firestore (I did check the debugger) but somehow, not all of them get loaded in the recyclerView. The itemViewHolder is only loaded with how I defined it as an XML, fields filled with lore Ipsum.
This would be my code:
HomeFragment:
public class HomeFragment extends Fragment {
private RecyclerView recyclerView;
private RecyclerViewAdapter recyclerViewAdapter;
private boolean isLoading = false;
private ArrayList<String> rowsArrayList = new ArrayList<>();
public static ArrayList<Post> appliedToList = new ArrayList<>();
private User currentUser = new User();
private View root;
private TextView userState;
private FirebaseFirestore db = FirebaseFirestore.getInstance();
private String userId = FirebaseAuth.getInstance().getCurrentUser() != null ? FirebaseAuth.getInstance().getCurrentUser().getUid() : null;
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
root = inflater.inflate(R.layout.fragment_home, container, false);
setState();
appliedToPostsRetrieverFromHomePage(getContext());
checkForPostFragment();
recyclerView = root.findViewById(R.id.recyclerView);
initAdapter();
initScrollListener();
return root;
}
private void initAdapter() {
recyclerViewAdapter = new RecyclerViewAdapter(getActivity(), 2);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerView.setAdapter(recyclerViewAdapter);
}
private void initScrollListener() {
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(#NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
#Override
public void onScrolled(#NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
if (!isLoading) {
if (linearLayoutManager != null && linearLayoutManager.findLastCompletelyVisibleItemPosition() == rowsArrayList.size() - 1) {
//bottom of list!
loadMore();
isLoading = true;
}
}
}
});
}
private void loadMore() {
rowsArrayList.add(null);
recyclerViewAdapter.notifyItemInserted(rowsArrayList.size() - 1);
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
rowsArrayList.remove(rowsArrayList.size() - 1);
int scrollPosition = rowsArrayList.size();
recyclerViewAdapter.notifyItemRemoved(scrollPosition);
int currentSize = scrollPosition;
int nextLimit = currentSize + 10;
while (currentSize - 1 < nextLimit) {
rowsArrayList.add("Item " + currentSize);
currentSize++;
}
recyclerViewAdapter.notifyDataSetChanged();
isLoading = false;
}
}, 2000);
}
#Override
public void onAttachFragment(#NonNull Fragment fragment) {
super.onAttachFragment(fragment);
}
RecyclerViewAdapter:
All view types represent kind of the same layout, the only difference between them is what is wrote on a certain button. Remember, some of the posts are successfully loaded!
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final int VIEW_TYPE_APPLY = 0;
private final int VIEW_TYPE_MORE = 1;
private final int VIEW_TYPE_BEGIN = 2;
private final int VIEW_TYPE_PENDING = 3;
private final int VIEW_TYPE_END = 4;
private final int VIEW_TYPE_ON_GOING = 5;
private final int VIEW_TYPE_LOADING = 6;
private ArrayList<Post> list = new ArrayList();
private static final String TAG = RecyclerViewAdapter.class.getSimpleName();
private Context context;
private User currentUser;
private int recyclerType;
static ArrayList<User> applicantsList = new ArrayList<>();
private String userId = FirebaseAuth.getInstance().getCurrentUser() != null ? FirebaseAuth.getInstance().getCurrentUser().getUid() : null;
private FirebaseFirestore db = FirebaseFirestore.getInstance();
public RecyclerViewAdapter(Context context, int recyclerType) {
this.context = context;
this.recyclerType = recyclerType;
if (recyclerType == 0) {
myPostsRetriever(context);
} else if (recyclerType == 1) {
appliedToPostsRetriever(context);
} else if (recyclerType == 2) {
homePostsRetriever(context);
}
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
if (viewType == VIEW_TYPE_APPLY) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_row_apply, parent, false);
return new ItemViewHolder(view);
} else if (viewType == VIEW_TYPE_MORE) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_row_more, parent, false);
return new LoadingViewHolder(view);
} else if (viewType == VIEW_TYPE_BEGIN) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_row_begin, parent, false);
return new LoadingViewHolder(view);
} else if (viewType == VIEW_TYPE_PENDING) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_row_pending, parent, false);
return new LoadingViewHolder(view);
} else if (viewType == VIEW_TYPE_END) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_row_end, parent, false);
return new LoadingViewHolder(view);
} else if (viewType == VIEW_TYPE_ON_GOING) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_row_on_going, parent, false);
return new LoadingViewHolder(view);
} else {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_loading, parent, false);
return new LoadingViewHolder(view);
}
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder viewHolder, int position) {
if (viewHolder instanceof ItemViewHolder) {
populateItemRows((ItemViewHolder) viewHolder, position);
} else if (viewHolder instanceof LoadingViewHolder) {
showLoadingView((LoadingViewHolder) viewHolder, position);
}
}
#Override
public int getItemCount() {
return list == null ? 0 : list.size();
}
#Override
public int getItemViewType(int position) {
if (list.get(position) != null) {
if (!list.get(position).getOwner().equals(userId) &&
!checkIfAlreadyAppliedToPost(position) &&
list.get(position).getMinNeededPersons() >= list.get(position).getApplicants()) {
return VIEW_TYPE_APPLY;
} else if (recyclerType == 1) {
return VIEW_TYPE_MORE;
} else if (list.get(position).getOwner().equals(userId) && timeCheck(list.get(position))) {
return VIEW_TYPE_BEGIN;
} else if (list.get(position).getOwner().equals(userId) && checkIfStarted(position)
|| !list.get(position).getOwner().equals(userId) && checkIfAlreadyAppliedToPost(position) && !checkIfStarted(position)) {
return VIEW_TYPE_PENDING;
} else if (list.get(position).getOwner().equals(userId) && checkIfStarted(position)) {
return VIEW_TYPE_END;
} else if (!list.get(position).getOwner().equals(userId) && checkIfStarted(position)){
return VIEW_TYPE_ON_GOING;
}else if (list.get(position).getOwner().equals(userId))
return VIEW_TYPE_MORE;
}
return VIEW_TYPE_LOADING;
}
private class ItemViewHolder extends RecyclerView.ViewHolder {
TextView title;
TextView description;
TextView location;
TextView minNeededPersons;
TextView maxNeededPersons;
TextView reward;
TextView time;
CheckBox physical;
Button button;
ItemViewHolder(#NonNull View itemView) {
super(itemView);
title = itemView.findViewById(R.id.postTitle);
description = itemView.findViewById(R.id.postDescription);
location = itemView.findViewById(R.id.postLocationText);
time = itemView.findViewById((R.id.postDateAndTime));
minNeededPersons = itemView.findViewById(R.id.people);
maxNeededPersons = itemView.findViewById(R.id.people);
reward = itemView.findViewById(R.id.reward);
physical = itemView.findViewById(R.id.checkBox2);
button = itemView.findViewById(R.id.applyButton);
}
}
private class LoadingViewHolder extends RecyclerView.ViewHolder {
ProgressBar progressBar;
LoadingViewHolder(#NonNull View itemView) {
super(itemView);
progressBar = itemView.findViewById(R.id.progressBar);
}
}
private void showLoadingView(LoadingViewHolder viewHolder, int position) {
}
private void populateItemRows(ItemViewHolder viewHolder, int position) {
Post item = list.get(position);
viewHolder.title.setText(item.getTheTitle());
viewHolder.description.setText(item.getDescription());
viewHolder.location.setText(item.getLocation());
viewHolder.location.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent showLocation = new Intent(context, MapsActivity.class);
context.startActivity(showLocation);
}
});
viewHolder.minNeededPersons.setText(String.valueOf(item.getMinNeededPersons()));
viewHolder.maxNeededPersons.setText(String.valueOf(item.getMaxPersonsNeeded()));
viewHolder.reward.setText(String.valueOf(item.getReward()));
viewHolder.physical.setChecked(item.isPhysical());
Date timeAndDate = item.getTime().toDate();
viewHolder.time.setText(new SimpleDateFormat("HH:mm dd.MM.yyyy").format(timeAndDate));
viewHolder.button.setOnClickListener(new View.OnClickListener() {
#SuppressLint("SetTextI18n")
#Override
public void onClick(View v) {
if (viewHolder.button.getText().equals(context.getResources().getString(R.string.apply))) {
onApplyTapped(position);
viewHolder.button.setText(R.string.pending);
viewHolder.button.setBackgroundColor(Color.parseColor("#F2CF59"));
viewHolder.button.setClickable(false);
} else if (viewHolder.button.getText().equals(context.getResources().getString(R.string.begin_job))) {
onBeginTapped(position);
viewHolder.button.setText(R.string.end_job);
viewHolder.button.setBackgroundColor(Color.parseColor("#F8CA9D"));
} else if (viewHolder.button.getText().equals(context.getResources().getString(R.string.end_job))) {
onEndTapped(position);
viewHolder.button.setBackgroundColor(Color.parseColor("#FB8E7E"));
viewHolder.button.setClickable(false);
viewHolder.button.setText(R.string.finished);
}
}
});
viewHolder.itemView.findViewById(R.id.seePostButton).setOnClickListener(new View.OnClickListener()
{ not relevant }
private void homePostsRetriever(Context context) {
FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
rootRef.collectionGroup("posts").limit(10).get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
#Override
public void onSuccess(QuerySnapshot documentSnapshots) {
for (DocumentSnapshot documentSnapshot : documentSnapshots.getDocuments()) {
Post post = new Post();
post.setAvailability(documentSnapshot.getBoolean("available"));
post.setTitle(documentSnapshot.getString("title"));
post.setDescription(documentSnapshot.getString("description"));
post.setLocation(documentSnapshot.getString("location"));
post.setApplicants(documentSnapshot.getLong("applicants").intValue());
post.setOwner(documentSnapshot.getString("owner"));
post.setMinNeededPersons(documentSnapshot.getLong("minNrOfPeople").intValue());
post.setMaxPersonsNeeded(documentSnapshot.getLong("maxNrOfPeople").intValue());
post.setReward(Objects.requireNonNull(documentSnapshot.getLong("reward")).floatValue());
post.setPhysical(documentSnapshot.getBoolean("physicalExcertion"));
post.setTime(documentSnapshot.getTimestamp("time"));
post.setId(documentSnapshot.getId());
post.setStarted(documentSnapshot.getBoolean("started"));
list.add(post);
}
notifyDataSetChanged();
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(context, "No document found", Toast.LENGTH_SHORT).show();
}
});
}
I don't think you are calling bind methods correctly, try:
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder viewHolder, int position) {
if (viewHolder instanceof ItemViewHolder) {
ItemViewHolder holder = (ItemViewHolder)viewHolder;
holder.populateItemRows(holder, position);
} else if (viewHolder instanceof LoadingViewHolder) {
LoadingViewHolder holder = (LoadingViewHolder)viewHolder;
holder.showLoadingView(holder , position);
}
}
Also this method:
private void populateItemRows(ItemViewHolder viewHolder, int position) {
.....
....
....
}
Is not found in your ItemViewHolder class
I am using Recyclerview with multiple ViewTypes.I have two Model classes for two different type of item in recyclerview as.I want to display two different type of item in same RecyclerView
My RecyclerViewAdapter is
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context context;
ArrayList<OneView> oneList;
ArrayList<TwoView> twoList;
public RecyclerAdapter(Context context,ArrayList<OneView> oneList,ArrayList<TwoView> twoList){
this.context=context;
this.oneList=oneList;
this.twoList=twoList;
}
#Override
public int getItemViewType(int position) {
switch (position){
case 0:
return 0;
case 1:
return 1;
}
return -1;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
int layout=0;
RecyclerView.ViewHolder viewHolder;
if(viewType==0){
layout=R.layout.oneview;
View one= LayoutInflater.from(parent.getContext()).inflate(layout,parent,false);
return new ViewHolder(one);
}else if(viewType==1){
layout=R.layout.twoview;
View two= LayoutInflater.from(parent.getContext()).inflate(layout,parent,false);
return new SecondView(two);
}else {
return null;
}
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
int viewType=holder.getItemViewType();
switch (viewType){
case 0:
OneView oneView=oneList.get(position);
((ViewHolder)holder).name.setText(oneView.getName());
break;
case 1:
TwoView twoView=twoList.get(position);
((SecondView)holder).name.setText(twoView.getName());
((SecondView)holder).address.setText(twoView.getAddress());
break;
default:
break;
}
}
#Override
public int getItemCount() {
return (this.oneList.size()+this.twoList.size());
}
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView name;
public ViewHolder(View itemView) {
super(itemView);
name=(TextView)itemView.findViewById(R.id.nameOne);
}
}
public class SecondView extends RecyclerView.ViewHolder {
private TextView name,address;
public SecondView(View itemView) {
super(itemView);
name=(TextView)itemView.findViewById(R.id.nameTwo);
address=(TextView)itemView.findViewById(R.id.address);
}
}
}
I want to display two type of item in same RecyclerView.But I am getting Attempt to write to field 'int android.support.v7.widget.RecyclerView$ViewHolder.mItemViewType' on a null object reference exception. How to resolve this ?
here is the complete example. I've used a RecyclerView with Multiple View Type. My scenario was, I have to show "cuisine list" [which is a horizontal view of multiple cuisines], then "number of restaurant", then "restaurant list".
so, i've used VIEW_RESTAURANT for restaurant view, VIEW_CUISINE for cuisine, VIEW_INFO for number of restaurant. As for my case, there's pagination, so VIEW_PROGRESS is used for showing progress bar at the bottom [by that time new set of data is fetch, if avaiable], VIEW_NO_DATA is used if restaurant list is empty.
hopefully from here, You can manage based on your requirement.
public class HomeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private String TAG = HomeAdapter.class.getSimpleName();
class ViewType {
int VIEW_PROGRESS = 1;
int VIEW_NO_DATA = 2;
int VIEW_RESTAURANT = 3;
int VIEW_CUISINE = 4;
int VIEW_INFO = 6;
}
private ViewType mViewType = new ViewType();
private Context mContext;
private int mCuisineItem = 1;
private int mInfoItem = 1;
private int mShowNoItem = 0;
private boolean mIsLoading;
private int mRestaurantNumber;
private int mCurrentPage;
private List<Data> mDataList;
private List<CuisineData> mCuisines;
private PaginationListener mPaginationListener;
private HorizontalPaginationListener mHorizontalPaginationListener;
private SearchResultClickListener mSearchResultClickListener;
private String mFrom;
public HomeAdapter(Context context, List<Data> dataList, List<CuisineData> cuisines, RecyclerView recyclerView, SearchResultClickListener searchResultClickListener) {
mContext = context;
mDataList = dataList;
mCuisines = cuisines;
mSearchResultClickListener = searchResultClickListener;
if (recyclerView.getLayoutManager() instanceof LinearLayoutManager) {
final LinearLayoutManager llManager = (LinearLayoutManager) recyclerView.getLayoutManager();
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int visible_threshold = 1;
int total_item_count = llManager.getItemCount();
int last_visible_item = llManager.findLastVisibleItemPosition();
if (!mIsLoading && total_item_count <= (last_visible_item + visible_threshold)) {
if (mPaginationListener != null) mPaginationListener.onPagination();
mIsLoading = true;
}
}
});
}
}
public void setmPaginationListener(PaginationListener paginationListener) {
mPaginationListener = paginationListener;
}
public void setmHorizontalPaginationListener(HorizontalPaginationListener horizontalPaginationListener) {
mHorizontalPaginationListener = horizontalPaginationListener;
}
public void setLoaded() {
mIsLoading = false;
}
public void setmRestaurantNumber(int restaurantNumber) {
mRestaurantNumber = restaurantNumber;
}
public void setmCurrentPage(int currentPage) {
mCurrentPage = currentPage;
}
public void addCuisine(String from) {
mFrom = from;
notifyDataSetChanged();
}
public void addCuisines(List<CuisineData> cuisines, String from) {
mFrom = from;
mCuisines.clear();
mCuisines = cuisines;
notifyDataSetChanged();
}
public void addRestaurants(List<Data> dataList) {
mShowNoItem = 0;
if(mCurrentPage == 1) notifyItemChanged(1);
if (mCurrentPage == 1) notifyItemChanged(2);
int insert_index = mDataList.size();
int pos_start = insert_index + mCuisineItem + mInfoItem;
mDataList.addAll(insert_index, dataList);
notifyItemRangeInserted(pos_start, dataList.size());
}
public void removeRestaurants() {
mShowNoItem = 1;
mDataList.clear();
mDataList = new ArrayList<>();
notifyItemRangeRemoved(mCuisineItem + mInfoItem, mDataList.size());
notifyItemChanged(2);
}
public void addProgressBar(Data data) {
mDataList.add(data);
notifyItemInserted(getItemCount() - 1);
}
public void removeProgressBar() {
if (mDataList.size() > 0) {
mDataList.remove(mDataList.size() - 1);
notifyItemRemoved(mCuisineItem + mInfoItem + mDataList.size());
}
}
public void removeAll() {
mDataList.clear();
mCuisines.clear();
mShowNoItem = 0;
notifyDataSetChanged();
}
#Override
public int getItemCount() {
return mDataList.size() + mShowNoItem + mCuisineItem + mInfoItem;
}
#Override
public int getItemViewType(int position) {
if (position == 0) return mViewType.VIEW_CUISINE;
if (position == 1) return mViewType.VIEW_INFO;
return mShowNoItem == 0 ? (mDataList.get(position - (mCuisineItem + mInfoItem)) != null ? mViewType.VIEW_RESTAURANT : mViewType.VIEW_PROGRESS)
: mViewType.VIEW_NO_DATA;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == mViewType.VIEW_CUISINE) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_horizontal_cuisines, parent, false);
return new ViewHolderCuisinesList(mContext, view, mHorizontalPaginationListener);
}
if (viewType == mViewType.VIEW_INFO) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_restaurant_number, parent, false);
return new ViewHolderRestaurantNumber(mContext, view);
}
if (mShowNoItem == 0) {
if (viewType == mViewType.VIEW_RESTAURANT) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.food_item_nearest_restaurant, parent, false);
return new ViewHolderRestaurant(mContext, view, mSearchResultClickListener);
} else if (viewType == mViewType.VIEW_PROGRESS) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_progress, parent, false);
return new ViewHolderProgress(view);
}
} else {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_empty, parent, false);
return new ViewHolderEmpty(view);
}
return null;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder instanceof ViewHolderSearch) {
((ViewHolderSearch) holder).onBind();
}
if (holder instanceof ViewHolderCuisinesList) {
if (!TextUtils.isEmpty(mFrom)) {
if (mFrom.equalsIgnoreCase(AppConstants.CUISINES))
((ViewHolderCuisinesList) holder).onBind(mCuisines);
else if (mFrom.equalsIgnoreCase(AppConstants.CUISINE))
((ViewHolderCuisinesList) holder).onBind_();
}
}
if (holder instanceof ViewHolderRestaurantNumber) {
((ViewHolderRestaurantNumber) holder).onBind(mRestaurantNumber);
}
if (mShowNoItem == 0) {
if (holder instanceof ViewHolderRestaurant) {
((ViewHolderRestaurant) holder).onBind(position - (mCuisineItem + mInfoItem), mDataList.get(position - (mCuisineItem + mInfoItem)));
} else if (holder instanceof ViewHolderProgress) {
((ViewHolderProgress) holder).onBind();
}
} else {
if (holder instanceof ViewHolderEmpty) {
((ViewHolderEmpty) holder).onBind(mContext.getString(R.string.no_result_found));
}
}
}
}
I am making an app in which I want to set images onto gridview and on itemclick I want to show the description of an image via textview. I have already done the setting of images onto gridview, but now I want to do the second part of it.
Following Images shows the visualization of The layout :
Before :
After :
Basically, I want to Add a new layout in between of 2 rows of gridview below the clicked image. I have done a lot of research and also seen many libraries and StackOverflow answers but can't figure out to do so. I need example code to do so for gridview or any other views. Thanks.
All the stackoverflow Answers and libraries that i have gone through :=
Android expandable GridView like Google images
Add view between 2 rows Gridview
Dynamically adding a whole row in GridView, or splitting the View
Libraries ->
https://github.com/thewaychung/ExpandableGridView
https://github.com/paolorotolo/ExpandableHeightListView
You can try the following approach for your reference :
I am using text view instead of ImageView. But the concept remain same.
It is displayed something like this.
Const.java : Class to keep constants.
public class Const {
public static final int DES_VIEW=0;
public static final int FOOD_VIEW=1;
public static final int FAKE_VIEW=2;
public static final int COLUMN_NUMBER = 2;
}
RowData.java : An Interface which will be used by the adapter class to get view type of each element.
public interface RowData {
int getViewType();
}
FoodItem.java : Just a plain pojo class which implements RowData ( The parent item FoodItem item 0 is populated )
public class FoodItem implements RowData{
public int getViewType() {
return viewType;
}
public void setViewType(int viewType) {
this.viewType = viewType;
}
private int viewType;
public boolean isExpanded() {
return isExpanded;
}
public void setExpanded(boolean expanded) {
isExpanded = expanded;
}
private boolean isExpanded;
public String getFoodName() {
return foodName;
}
public void setFoodName(String foodName) {
this.foodName = foodName;
}
private String foodName;
public String getDescription() {
return description == null ? "DEFAULT" : description;
}
public void setDescription(String description) {
this.description = description;
}
private String description;
}
FakeData.java : Pojo class to populate empty views.
public class FakeData implements RowData {
#Override
public int getViewType() {
return Const.FAKE_VIEW;
}
}
FoodAdapter.java : Adapter class.
public class FoodAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public void setFoodItems(List<RowData> foodItems) {
this.foodItems = foodItems;
// addBlankViews();
}
private List<RowData> foodItems;
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view;
switch (viewType) {
case Const.FOOD_VIEW:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout, parent, false);
return new VH(view);
case Const.DES_VIEW:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.des, parent, false);
return new DesView(view);
case Const.FAKE_VIEW:
Log.e("CALLED", " ---> " + viewType);
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout, parent, false);
return new FakeView(view);
default:
return null;
}
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
int view = getItemViewType(position);
switch (view) {
case Const.FAKE_VIEW: {
FakeView fakeView = (FakeView) holder;
Log.e("CALLED", position + " " + view);
}
break;
case Const.DES_VIEW: {
DesView desView = (DesView) holder;
desView.setData((FoodItem) getFoodItem(position));
}
break;
case Const.FOOD_VIEW: {
VH foodView = (VH) holder;
foodView.setData((FoodItem) getFoodItem(position));
}
break;
}
}
RowData getFoodItem(int position) {
if (foodItems != null) {
return foodItems.get(position);
}
return null;
}
#Override
public int getItemViewType(int position) {
RowData foodItem = getFoodItem(position);
if (foodItem != null) {
return foodItem.getViewType();
}
return -1;
}
#Override
public int getItemCount() {
if (foodItems == null) {
return 0;
} else {
return foodItems.size();
}
}
class VH extends RecyclerView.ViewHolder {
TextView foodItemName;
public VH(View itemView) {
super(itemView);
foodItemName = itemView.findViewById(R.id.food_item);
foodItemName.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FoodAdapter.this.onClick(getAdapterPosition());
}
});
}
void setData(FoodItem data) {
foodItemName.setText(data.getFoodName());
}
}
class DesView extends RecyclerView.ViewHolder {
TextView foodDesView;
public DesView(View itemView) {
super(itemView);
foodDesView = itemView.findViewById(R.id.des_item);
foodDesView.setTextColor(Color.BLUE);
}
void setData(FoodItem data) {
foodDesView.setText(data.getDescription());
}
}
class FakeView extends RecyclerView.ViewHolder {
public FakeView(View itemView) {
super(itemView);
}
}
private int currentExpandedIndex = -1;
private void onClick(int position) {
// calculation to show and hide the child view (with magenta background ).
if (currentExpandedIndex != -1) {
foodItems.remove(currentExpandedIndex);
currentExpandedIndex = -1;
notifyDataSetChanged();
return;
}
int startIndex = position % Const.COLUMN_NUMBER;
if (startIndex == 0) {
startIndex = position;
} else {
startIndex = position - startIndex;
}
startIndex = startIndex + Const.COLUMN_NUMBER;
if (currentExpandedIndex == -1) {
FoodItem des = new FoodItem();
des.setViewType(Const.DES_VIEW);
FoodItem foodItem = (FoodItem) getFoodItem(position);
des.setDescription(foodItem.getDescription());
foodItems.add(startIndex, des);
currentExpandedIndex = startIndex;
}
notifyDataSetChanged();
}
}
MainActivity.java : Activity class.
public class MainActivity extends AppCompatActivity {
private FoodAdapter foodAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RecyclerView recyclerView = findViewById(R.id.reycleView);
((SimpleItemAnimator) recyclerView.getItemAnimator()).setSupportsChangeAnimations(false);
foodAdapter = new FoodAdapter();
foodAdapter.setFoodItems(getFoodItems());
GridLayoutManager mLayoutManager = new GridLayoutManager(this,Const.COLUMN_NUMBER);
mLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
#Override
public int getSpanSize(int position) {
switch (foodAdapter.getItemViewType(position)) {
case Const.DES_VIEW:
return Const.COLUMN_NUMBER;
default:
return 1;
}
}
});
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.setHasFixedSize(true);
recyclerView.setAdapter(foodAdapter);
}
private List<RowData> foodItems;
private List<RowData> getFoodItems() {
foodItems = new ArrayList<>();
for (int i = 0; i < 18; i++) {
FoodItem foodItem = new FoodItem();
foodItem.setFoodName(" FoodItem item " + i);
foodItem.setExpanded(false);
foodItem.setDescription("Fake des of " + i);
foodItem.setViewType(Const.FOOD_VIEW);
foodItems.add(foodItem);
}
// calculation to add empty view.
// these view will be added when, there is shortage of parent views to fill row completely
int size = foodItems.size();
int blankView = size % Const.COLUMN_NUMBER;
if (blankView != 0) {
blankView = Const.COLUMN_NUMBER - blankView;
for (int i = 0; i < blankView; i++) {
foodItems.add(new FakeData());
}
}
return foodItems;
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="check.service.com.genericrecylerview.MainActivity">
<android.support.v7.widget.RecyclerView
android:id="#+id/reycleView"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
des.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:orientation="vertical"
android:background="#color/colorAccent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/des_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:orientation="vertical"
android:layout_height="wrap_content">
<TextView
android:id="#+id/food_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
#Override
public void onBindViewHolder(ContactViewHolder contactViewHolder, int i)
{
// below I put layout show hide logic.this logic working but when i scroll the layout disturb.
if (month_value.equalsIgnoreCase("") || !(month_value.equalsIgnoreCase(ci.monthgrpmore_str))) {
month_value = ci.monthgrpmore_str;
contactViewHolder.dfgnew.setVisibility(View.VISIBLE);
contactViewHolder.product_header2.setVisibility(View.VISIBLE);
} else {
contactViewHolder.dfgnew.setVisibility(View.GONE);
contactViewHolder.product_header2.setVisibility(View.GONE);
}
if (Global_Data.target_grpby.equalsIgnoreCase("By Product")) {
contactViewHolder.month_grpby.setText("Product Sub Category");
}
}
// I find answer of my problem just replace some code in onBindViewHolder
if (month_value.equalsIgnoreCase("") || !(month_value.equalsIgnoreCase(ci.monthgrpmore_str))) {
month_value = ci.monthgrpmore_str;
contactViewHolder.dfgnew.setVisibility(View.VISIBLE);
contactViewHolder.product_header2.setVisibility(View.VISIBLE);
} else {
contactViewHolder.dfgnew.setVisibility(View.GONE);
contactViewHolder.product_header2.setVisibility(View.GONE);
}
//replace above cobe with below code inside onBindViewHolder
if (i > 0 && !(contactList.get(i).monthgrpmore_str.equalsIgnoreCase(contactList.get(i-1).monthgrpmore_str))) {
month_value = ci.monthgrpmore_str;
contactViewHolder.dfgnew.setVisibility(View.VISIBLE);
contactViewHolder.product_header2.setVisibility(View.VISIBLE);
} else {
if(i != 0)
{
contactViewHolder.dfgnew.setVisibility(View.GONE);
contactViewHolder.product_header2.setVisibility(View.GONE);
}
}
// And my full adapter code is below.
public class GrpbyMore_Adapter extends RecyclerView.Adapter<GrpbyMore_Adapter.ContactViewHolder> {
int a=0;
String month_value = "";
private List<TargetValue_info> contactList;
private List<TargetValue_info> contactListnew;
public GrpbyMore_Adapter(List<TargetValue_info> contactList) {
this.contactList = contactList;
this.contactListnew = contactList;
}
#Override
public int getItemCount() {
return contactList.size();
}
#Override
public void onBindViewHolder(ContactViewHolder contactViewHolder, int i)
{
++a;
// if(a <= contactListnew.size()) {
TargetValue_info ci = contactList.get(i);
// if (contactViewHolder != null) {
contactViewHolder.setIsRecyclable(false);
contactViewHolder.prdcatg_more.setText(ci.prdcatg_morestr);
contactViewHolder.month_more.setText(ci.monthgrpmore_str);
if (month_value.equalsIgnoreCase("") || !(month_value.equalsIgnoreCase(ci.monthgrpmore_str))) {
month_value = ci.monthgrpmore_str;
contactViewHolder.dfgnew.setVisibility(View.VISIBLE);
contactViewHolder.product_header2.setVisibility(View.VISIBLE);
} else {
contactViewHolder.dfgnew.setVisibility(View.GONE);
contactViewHolder.product_header2.setVisibility(View.GONE);
}
if (Global_Data.target_grpby.equalsIgnoreCase("By Product")) {
contactViewHolder.month_grpby.setText("Product Sub Category");
}
}
#Override
public ContactViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View itemView = null;
itemView = LayoutInflater.
from(viewGroup.getContext()).
inflate(R.layout.summary2_adapter, viewGroup, false);
return new ContactViewHolder(itemView);
}
public static class ContactViewHolder extends RecyclerView.ViewHolder {
protected TextView prdcatg_more;
protected TextView month_more;
public ContactViewHolder(View v) {
super(v);
prdcatg_more = (TextView) v.findViewById(R.id.prdcatg_more);
month_grpby = (TextView) v.findViewById(R.id.month_grpby);
dfgnew = (LinearLayout) v.findViewById(R.id.dfgnew);
product_header2 = (LinearLayout) v.findViewById(R.id.product_header2);
}
}
}
I have a fragment that contains a view pager, a recycler view, etc.
I want to place all of that inside a scroll view , but it just refuses to scroll. Am I missing something here?
I've tried setting fillViewport false, and removing the scrollbars:none, and a couple of other things but nothing helps..
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fillViewport="true"
android:scrollbars="none">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<LinearLayout
android:id="#+id/headerLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="abc"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/image"/>
</LinearLayout>
<android.support.v7.widget.RecyclerView
android:layout_below="#id/headerLayout"
android:id="#+id/recyclerView"
android:scrollbars="none"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<android.support.v4.view.ViewPager
android:layout_below="#id/recyclerView"
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v4.view.PagerTabStrip
android:id="#+id/pager_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"/>
</android.support.v4.view.ViewPager>
</RelativeLayout>
</ScrollView>
As I responded in comment, check the adapter class of RecyclerView. I won't be explaining it as it is too big to explain. But for starters follow the link Recyclerview and handling different type of row inflation
For the code below you can relate it with StyFi app from google store
public class FeedRecyclerStickyHeaderAdapter<T> extends RecyclerStickyTypeWrapper<T>
implements StickyRecyclerHeadersAdapter<RecyclerView.ViewHolder> {
private static final String TAG = FeedRecyclerStickyHeaderAdapter.class.getSimpleName();
public static final int VIEW_LOOK = 0;
public static final int VIEW_PRODUCT = 1;
public static final int VIEW_BLOG = 2;
public static final int VIEW_BRAND = 3;
public static final int VIEW_PROGRESS = 4;
public static final int VIEW_AD = 5;
public static final int VIEW_NEW_ARRIVALS = 6;
public static final int VIEW_FEATURED_BRANDS = 7;
public static final int VIEW_BIG_BANNER = 8;
public static final int VIEW_BRAND_FEED = 9;
private static final int TOTAL_VIEWS = 10;
private OnInteractionListener listener;
private OnButtonClickListener callback;
private Fragment fragment;
private Handler handler;
private TimerTask task;
private ArrayList<RecyclerView.ViewHolder> holderArrayList;
public FeedRecyclerStickyHeaderAdapter(Activity context, #NonNull List<T> objects, #NonNull OnInteractionListener listener) {
super();
this.context = context;
this.objects = objects;
this.listener = listener;
holderArrayList = new ArrayList<>(objects.size());
}
public FeedRecyclerStickyHeaderAdapter(Activity context, #NonNull List<T> objects, Fragment fragment,
#NonNull OnInteractionListener listener) {
super();
this.context = context;
this.objects = objects;
this.fragment = fragment;
this.listener = listener;
}
/**
* Used for feeds for adding products to wishlist
*
* #param context
* #param objects
* #param fragment
* #param listener
* #param callback
*/
public FeedRecyclerStickyHeaderAdapter(Activity context, #NonNull List<T> objects, Fragment fragment,
#NonNull OnInteractionListener listener, #NonNull OnButtonClickListener callback) {
super();
this.context = context;
this.objects = objects;
this.fragment = fragment;
this.listener = listener;
this.callback = callback;
}
#Override
public int getItemViewType(int position) {
if (position > -1 && position < objects.size()) {
if (objects.get(position) instanceof Feed) {
switch (((Feed) objects.get(position)).getViewType()) {
case Feed.LOOK_VIEW:
return VIEW_LOOK;
case Feed.BLOG_VIEW:
return VIEW_BLOG;
case Feed.PRODUCT_VIEW:
return VIEW_PRODUCT;
case Feed.PROGRESS_VIEW:
return VIEW_PROGRESS;
case Feed.FEATURED_BRANDS_VIEW:
return VIEW_FEATURED_BRANDS;
case Feed.NEW_ARRIVAL_VIEW:
return VIEW_NEW_ARRIVALS;
case Feed.AD_VIEW:
return VIEW_AD;
case Feed.BRAND_VIEW:
return VIEW_BRAND;
}
} else if (objects.get(position) instanceof BrandFeed) {
switch (((BrandFeed) objects.get(position)).getViewType()) {
case BrandFeed.AD_VIEW:
return VIEW_AD;
case BrandFeed.BIG_BANNER_VIEW:
return VIEW_BIG_BANNER;
case BrandFeed.BRAND_FEED_VIEW:
return VIEW_BRAND_FEED;
case BrandFeed.PROGRESS_VIEW:
return VIEW_PROGRESS;
}
} else if (objects.get(position) instanceof Looks) {
if (null != ((Looks) objects.get(position)).getLookId())
return VIEW_LOOK;
else
return VIEW_PROGRESS;
} else if (null == objects.get(position))
return VIEW_PROGRESS;
}
return super.getItemViewType(position);
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v;
switch (viewType) {
case VIEW_LOOK: {
ViewHolderLook holder = new ViewHolderLook(LayoutInflater.from(context)
.inflate(R.layout.listitem_look, parent, false));
if (2 <= context.getResources().getInteger(R.integer.gridviewcolumn)) {
initializeHeaders(holder.view, holder);
}
return holder;
}
case VIEW_PRODUCT: {
ViewHolderProduct holder = new ViewHolderProduct(LayoutInflater.from(context)
.inflate(R.layout.listitem_new_product, parent, false));
if (2 <= context.getResources().getInteger(R.integer.gridviewcolumn)) {
initializeHeaders(holder.view, holder);
}
return holder;
}
case VIEW_BLOG: {
ViewHolderBlog holder = new ViewHolderBlog(LayoutInflater.from(context)
.inflate(R.layout.blog_list_item_new, parent, false));
if (2 <= context.getResources().getInteger(R.integer.gridviewcolumn)) {
initializeHeaders(holder.view, holder);
}
return holder;
}
case VIEW_BRAND: {
ViewHolderBrands holder = new ViewHolderBrands(LayoutInflater.from(context)
.inflate(R.layout.listitem_feed_brand, parent, false));
if (2 <= context.getResources().getInteger(R.integer.gridviewcolumn)) {
initializeHeaders(holder.view, holder);
}
return holder;
}
case VIEW_PROGRESS: {
v = LayoutInflater.from(context).inflate(R.layout.dialog_progress, parent, false);
return new ViewHolderProgress(v);
}
case VIEW_AD: {
v = LayoutInflater.from(context).inflate(R.layout.listitem_offers, parent, false);
return new ViewHolderAd(v);
}
case VIEW_NEW_ARRIVALS: {
v = LayoutInflater.from(context).inflate(R.layout.listitem_new_arrivals, parent, false);
return new ViewHolderNewArrivals(v);
}
case VIEW_FEATURED_BRANDS: {
v = LayoutInflater.from(context).inflate(R.layout.listitem_featured_brands, parent, false);
return new ViewHolderFeaturedBrands(v);
}
case VIEW_BRAND_FEED: {
v = LayoutInflater.from(context).inflate(R.layout.listitem_brandfeed, parent, false);
return new ViewHolderBrandFeed(v);
}
case VIEW_BIG_BANNER: {
v = LayoutInflater.from(context).inflate(R.layout.listitem_brandfeed_big_banner, parent, false);
return new ViewHolderBigBanner(v);
}
}
return null;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (BuildConfig.DEBUG)
Log.d(TAG, "onBindViewHolder: " + position);
if (null != holder) {
if (holder instanceof ViewHolderLook) {
if (2 <= context.getResources().getInteger(R.integer.gridviewcolumn)) {
setHeadersData((ViewHolderLook<T>) holder, position);
}
bindLookView((ViewHolderLook<T>) holder, position);
} else if (holder instanceof ViewHolderProduct) {
if (2 <= context.getResources().getInteger(R.integer.gridviewcolumn)) {
setHeadersData((ViewHolderProduct<T>) holder, position);
}
bindProductView((ViewHolderProduct<T>) holder, position);
} else if (holder instanceof ViewHolderBlog) {
if (2 <= context.getResources().getInteger(R.integer.gridviewcolumn)) {
setHeadersData((ViewHolderBlog<T>) holder, position);
}
bindBlogView((ViewHolderBlog<T>) holder, position);
} else if (holder instanceof ViewHolderBrands) {
if (2 <= context.getResources().getInteger(R.integer.gridviewcolumn)) {
setHeadersData((ViewHolderBrands<T>) holder, position);
}
bindBrand((ViewHolderBrands<T>) holder, position);
} else if (holder instanceof ViewHolderAd)
bindAd((ViewHolderAd<T>) holder, position);
else if (holder instanceof ViewHolderNewArrivals)
bindNewArrival((ViewHolderNewArrivals<T>) holder, position);
else if (holder instanceof ViewHolderFeaturedBrands)
bindFeaturedBrands((ViewHolderFeaturedBrands<T>) holder, position);
else if (holder instanceof ViewHolderProgress) {
if (2 == context.getResources().getInteger(R.integer.gridviewcolumn)) {
StaggeredGridLayoutManager.LayoutParams layoutParams = (StaggeredGridLayoutManager.LayoutParams) holder.itemView.getLayoutParams();
layoutParams.setFullSpan(true);
holder.itemView.setLayoutParams(layoutParams);
}
} else if (holder instanceof ViewHolderBigBanner) {
bindBigBanner((ViewHolderBigBanner<T>) holder, position);
} else if (holder instanceof ViewHolderBrandFeed) {
bindBrandFeed((ViewHolderBrandFeed<T>) holder, position);
}
if (null == holderArrayList)
holderArrayList = new ArrayList<>();
if (null != objects && position != -1 && position < objects.size()) {
if (position < holderArrayList.size() || position == 0)
holderArrayList.add(position, holder);
else
holderArrayList.add(holder);
}
}
}
#Override
public long getHeaderId(int position) {
if (2 <= context.getResources().getInteger(R.integer.gridviewcolumn))
return -1;
switch (getItemViewType(position)) {
case VIEW_PROGRESS:
case VIEW_AD:
case VIEW_NEW_ARRIVALS:
case VIEW_FEATURED_BRANDS:
case VIEW_BIG_BANNER:
case VIEW_BRAND_FEED:
return -1;
default:
return getItem(position).hashCode();
}
}
#Override
public long getItemId(int position) {
return getItem(position).hashCode();
}
#Override
public RecyclerView.ViewHolder onCreateHeaderViewHolder(ViewGroup parent) {
StickyHeaderViewHolder<T> holder = new StickyHeaderViewHolder<T>(LayoutInflater.from(context)
.inflate(R.layout.listitem_header, parent, false));
initializeHeaders(holder.view, holder);
return holder;
}
#Override
public void onBindHeaderViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
if (BuildConfig.DEBUG)
Log.d(TAG, "onBindHeaderViewHolder: " + position);
if (viewHolder instanceof StickyHeaderViewHolder) {
setHeadersData((StickyHeaderViewHolder) viewHolder, position);
}
}
/**
* Overloading function for setting headers for tabs for sticky headers
*
* #param holder
* #param position
*/
private void setHeadersData(StickyHeaderViewHolder holder, int position) {
holder.view.setOnClickListener(new View.OnClickListener() {
// This click listener is not working as sticky headers are just canvas and not views
// as desired for click listeners.
#Override
public void onClick(View v) {
if (null != v.getTag()) {
if (v.getTag() instanceof Looks) {
Looks data = (Looks) v.getTag();
openLook(data);
} else if (v.getTag() instanceof Brand) {
Brand data = (Brand) v.getTag();
openBrand(data.getBrandId(), data.getBrandName());
} else if (v.getTag() instanceof Product) {
Product data = (Product) v.getTag();
openBrand(data.getBrandId(), data.getBrandName());
} else if (v.getTag() instanceof Blog) {
Blog data = (Blog) v.getTag();
}
}
}
});
final T type = getItem(position);
if (type instanceof Feed) {
Feed object = (Feed) type;
switch (object.getViewType()) {
case Feed.LOOK_VIEW: {
Looks data = object.getLook();
holder.imgHeaderDp.setImageUrl(data.getStylistImage(), MyApp.getInstance().getImageLoader());
holder.lblHeaderName.setText(data.getStylistName());
holder.lblHeaderTime.setText(TimeConversions.longToPrettyTimeString(data.getCreatedDate()));
holder.lblHeaderTime.setVisibility(View.VISIBLE);
holder.view.setVisibility(View.VISIBLE);
holder.view.setTag(data);
break;
}
case Feed.BLOG_VIEW: {
Blog data = object.getBlog();
// holder.imgHeaderDp.setImageUrl(data.getThumb(), MyApp.getInstance().getImageLoader());
holder.lblHeaderName.setText(data.getAuthorName());
holder.lblHeaderTime.setText(TimeConversions.longToPrettyTimeString(data.getPostedDate()));
//
holder.lblHeaderTime.setVisibility(View.VISIBLE);
holder.view.setVisibility(View.VISIBLE);
holder.view.setTag(data);
break;
}
case Feed.PRODUCT_VIEW: {
Product data = object.getProduct();
// holder.imgHeaderDp.setImageUrl(data.getProductThumbnail(), MyApp.getInstance().getImageLoader());
holder.lblHeaderName.setText(data.getBrandName());
holder.lblHeaderTime.setVisibility(View.GONE);
holder.view.setVisibility(View.VISIBLE);
holder.view.setTag(data);
break;
}
case Feed.BRAND_VIEW: {
Brand data = object.getBrand();
holder.imgHeaderDp.setImageUrl(data.getImgLogoUrl(), MyApp.getInstance().getImageLoader());
holder.lblHeaderName.setText(data.getBrandName());
holder.lblHeaderTime.setVisibility(View.GONE);
holder.view.setVisibility(View.VISIBLE);
holder.view.setTag(data);
}
}
} else if (objects.get(position) instanceof Looks) {
if (null != ((Looks) objects.get(position)).getLookId()) {
// Looks in Looks feed
Looks data = ((Looks) objects.get(position));
holder.imgHeaderDp.setImageUrl(data.getStylistImage(), MyApp.getInstance().getImageLoader());
holder.lblHeaderName.setText(data.getStylistName());
holder.lblHeaderTime.setText(TimeConversions.longToPrettyTimeString(data.getCreatedDate()));
holder.lblHeaderTime.setVisibility(View.VISIBLE);
holder.view.setVisibility(View.VISIBLE);
holder.view.setTag(data);
}
}
}
class ViewHolderLook<T> extends RecyclerView.ViewHolder {
// Header
RoundedNetworkImageView imgHeaderDp;
FontTextView lblHeaderName;
FontTextView lblHeaderTime;
View view;
// Body
FontTextView lblLookName, lblLookDesc;
CustomCheckbox chkFavorite;
ImageView btnShare;
SquareNetworkImageView imgLook;
public ViewHolderLook(View view) {
super(view);
chkFavorite = (CustomCheckbox) view.findViewById(R.id.chk_favorite);
btnShare = (ImageView) view.findViewById(R.id.btn_share);
imgLook = (SquareNetworkImageView) view.findViewById(R.id.img_look);
lblLookName = (FontTextView) view.findViewById(R.id.lbl_title);
lblLookDesc = (FontTextView) view.findViewById(R.id.lbl_desc);
// if it's tab then only initialize else not required
if (2 <= context.getResources().getInteger(R.integer.gridviewcolumn)) {
this.view = view.findViewById(R.id.header);
}
}
}
class ViewHolderBlog<T> extends RecyclerView.ViewHolder {
// Header
RoundedNetworkImageView imgHeaderDp;
FontTextView lblHeaderName;
FontTextView lblHeaderTime, lblReadFull;
View view;
View shareView, root;
LinearLayout llShare;
FontTextView lblBlogTitle, lblAuthor, lblRead, lblTime, lblDescription, lblLookCount;
FontButton btnCopyToClipboard, btnWhatsApp, btnEmail, btnFacebook, btnTwitter, btnGPlus, btnPinterest, btnInstagram;
SquareNetworkImageView imgBlog;
CustomNetworkImageView blog_image;
ImageView chkShare;
public ViewHolderBlog(View view) {
super(view);
lblBlogTitle = (FontTextView) view.findViewById(R.id.blog_title);
lblDescription = (FontTextView) view.findViewById(R.id.blog_description);
lblLookCount = (FontTextView) view.findViewById(R.id.lbl_looks_count);
lblAuthor = (FontTextView) view.findViewById(R.id.txt_author);
imgBlog = (SquareNetworkImageView) view.findViewById(R.id.iv_blogimage);
lblRead = (FontTextView) view.findViewById(R.id.txt_read);
lblTime = (FontTextView) view.findViewById(R.id.txt_timer);
llShare = (LinearLayout) view.findViewById(R.id.ll_share_container);
chkShare = (ImageView) view.findViewById(R.id.share);
blog_image = (CustomNetworkImageView) view.findViewById(R.id.blog_image);
lblReadFull = (FontTextView) view.findViewById(R.id.read_full);
this.root = view;
// if it's tab then only initialize else not required
if (2 <= context.getResources().getInteger(R.integer.gridviewcolumn)) {
this.view = view.findViewById(R.id.header);
}
}
}
class ViewHolderAd<T> extends RecyclerView.ViewHolder {
protected CustomViewPager viewPager;
protected LinearLayout llPage;
public ViewHolderAd(View view) {
super(view);
viewPager = (CustomViewPager) view.findViewById(R.id.view_pager);
llPage = (LinearLayout) view.findViewById(R.id.ll_page);
}
}
.
.
.
.
}
And this is the layout for the first Feed screen
<?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"
android:id="#+id/lookforu_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.mycompany.myapp.app.custom.widget.GifSwipeRefreshLayout
android:id="#+id/refresh_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<view
android:id="#+id/grid_view"
class="android.support.v7.widget.RecyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/half_padding"
android:gravity="center" />
</com.mycompany.myapp.app.custom.widget.GifSwipeRefreshLayout>
</RelativeLayout>