I have recycleview which is set to auto scroll. I am looking to implement onclicklistener such that new activity will open.
Here is my Recycleview
final int duration = 10;
final int pixelsToMove = 30;
private final Handler mHandler = new Handler(Looper.getMainLooper());
private final Runnable SCROLLING_RUNNABLE = new Runnable() {
#Override
public void run() {
top.smoothScrollBy(pixelsToMove, 0);
mHandler.postDelayed(this, duration);
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_home, container, false);
top = (RecyclerView) view.findViewById(R.id.top);
final LinearLayoutManager llm = new LinearLayoutManager(getActivity(),LinearLayoutManager.HORIZONTAL,false);
top.setLayoutManager(llm);
top.setHasFixedSize(true);
staggeredBooksAdapter = new TopAdapter(this, bookslist);
top.setAdapter(staggeredBooksAdapter);
//Recycleview
top.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);
int lastItem = llm.findLastCompletelyVisibleItemPosition();
if(lastItem == llm.getItemCount()-1){
mHandler.removeCallbacks(SCROLLING_RUNNABLE);
Handler postHandler = new Handler();
postHandler.postDelayed(new Runnable() {
#Override
public void run() {
top.setAdapter(null);
top.setAdapter(staggeredBooksAdapter);
mHandler.postDelayed(SCROLLING_RUNNABLE, 6000);
}}, 6000);
}
}
});
mHandler.postDelayed(SCROLLING_RUNNABLE, 6000);
and my adapter class is
public class TopAdapter extends RecyclerView.Adapter<TopAdapter.MyViewHolder> {
ArrayList<location> bookslist;
CardView cv;
location g;
private Home context;
public TopAdapter(Home context, ArrayList<location> bookslist){
this.bookslist = bookslist;
this.context = context; // add this as a field in your adapter class.
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_top,parent,false);
return new MyViewHolder(v);
}
public class MyViewHolder extends RecyclerView.ViewHolder {
TextView teacher_name,teacher_location;
LinearLayout profile_details;
ImageView iv;
MyViewHolder(final View itemView) {
super(itemView);
cv = (CardView) itemView.findViewById(R.id.teacher_name);
teacher_location = (TextView)
}
}
#Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
database = FirebaseDatabase.getInstance();
g = bookslist.get(position);
holder.teacher_name.setText(g.getSellername());
holder.profile_details.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
g = bookslist.get(position);
Intent intent = new Intent(v.getContext(), gender_details.class);
intent.putExtra(KEY_NAME, g.getSellername());
v.getContext().startActivity(intent);
}
});
#Override
public int getItemCount() {
return bookslist.size();
}
}
When I repetitively click, I am able to opens new activity with details based on position but I have no idea how It is happening and I can only reproduce same effect only after repeatedly clicking some item. But it doesn't happen often. I'm looking for permanent solution to opens new activity when I click any item from list of recycleview in one click.
Thanks in advance.
Your onClickListener setted for view with name profile_details and it is triggered only when you tap on (exactly) this view. Some of your elements may overlap this view, so your tap not work. It's explain what your startActivity triggered after some random number of taps in different parts of item.
Try to debug clicks on view and set this onItemClickListener to appropriate View/ViewGroup
P.S:
Also my advice is to not store any database related objects inside adapter (it's violation of single responsibility).
Also is bad practice to store activity start logic in adapter. See this answer: Can't resolve the Context or Application while navigating from Adapter of a fragment(A) to another Fragment (B)
Hope it will help :)
Related
So when i click on the 0 position of recyclerview to change the color of the view it also changes the color at 8th, 16th and 24th position (i have a total of 26 items in recyclerview), if i click on position 1 it changes color at 1st, 9th, 17th and 25th and so on. how do i fix this
My recyclerview adapter is
public class AdapterOccupiedRoomCleaning extends RecyclerView.Adapter<AdapterOccupiedRoomCleaning.ViewHolder> {
private List<ItemsAdapter> mList;
private Context mContext;
public AdapterOccupiedRoomCleaning(List<ItemsAdapter> list, Context context){
super();
mList = list;
mContext = context;
}
#NonNull
#Override
public AdapterOccupiedRoomCleaning.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int i) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.occupiedrooms_cleaning_item, parent, false);
ViewHolder viewHolder = new ViewHolder(v);
return viewHolder;
}
#Override
public void onBindViewHolder(#NonNull AdapterOccupiedRoomCleaning.ViewHolder viewHolder, int position) {
ItemsAdapter itemAdapter = mList.get(position);
((ViewHolder) viewHolder).setUrduText.setText(itemAdapter.getUrdutext());
((ViewHolder) viewHolder).setEnglishText.setText(itemAdapter.getEnglishText());
((ViewHolder) viewHolder).setCleaningImage.setImageResource(itemAdapter.getImage());
// ((ViewHolder) viewHolder).background.setOnClickListener(new View.OnClickListener() {
// #Override
// public void onClick(View v) {
//
// //viewHolder.background.setBackgroundColor(Color.parseColor("#08A467"));
//
// Toast.makeText(mContext, "Recycle Click " + viewHolder.setEnglishText.getText().toString(), Toast.LENGTH_SHORT).show();
// }
// });
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
viewHolder.background.setBackgroundColor(Color.parseColor("#08A467"));
}
});
}
#Override
public int getItemCount() {
//notifyDataSetChanged();
return mList.size();
}
class ViewHolder extends RecyclerView.ViewHolder{
public TextView setUrduText, setEnglishText;
public ImageView setCleaningImage;
public View background;
public ViewHolder(View itemView) {
super(itemView);
setUrduText = (TextView) itemView.findViewById(R.id.urduTextView);
setEnglishText = (TextView) itemView.findViewById(R.id.englishTextView);
setCleaningImage = (ImageView) itemView.findViewById(R.id.imageCleaning);
background = (View) itemView.findViewById(R.id.backgroundColor);
}
}
}
My java class is
public class OccupiedRoomCleaning extends AppCompatActivity {
String getQrCode, patientMRNO, roomNumber;
private RecyclerView mRecycleview;
private List<ItemsAdapter> mList = new ArrayList<>();
private AdapterOccupiedRoomCleaning mAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_occupied_room_cleaning);
getQrCode = getIntent().getExtras().getString("qrcode");
init();
addList();
adapter();
}
private void init(){
mRecycleview = findViewById(R.id.recyclerview);
}
private void addList(){
ItemsAdapter itemAdapter = new ItemsAdapter();
itemAdapter.setImage(R.drawable.pillowclean);
itemAdapter.setUrdutext("sdf");
itemAdapter.setEnglishText("Pillow Parachute Cover Cleaning");
mList.add(itemAdapter);
itemAdapter = new ItemsAdapter();
itemAdapter.setImage(R.drawable.bedclean);
itemAdapter.setUrdutext("sdfs");
itemAdapter.setEnglishText("Patient Bed Cleaning(Blood Spots)");
mList.add(itemAdapter);
//... more items
}
private void adapter(){
Log.d("anhtt","mlist : " +mList.size());
mAdapter = new AdapterOccupiedRoomCleaning(mList, this);
mRecycleview.setAdapter(mAdapter);
mRecycleview.setLayoutManager(new LinearLayoutManager(this));
}
}
what am i doing wrong here that it changes color at every 8th item
This seems likely to be a problem with the view recycling behavior of RecyclerView.
Generally, you're going to run into problems like this one any time you have some property of your ViewHolder that you only conditionally set inside onBindViewHolder(). That is, because you do not always update the background color of your ViewHolder, you'll get the "wrong" color when it is recycled and reused.
You will have to somehow store the "clicked" or "selected" state in your list of items, and then update the background color of your ViewHolder every time in onBindViewHolder(). Something like this:
#Override
public void onBindViewHolder(#NonNull AdapterOccupiedRoomCleaning.ViewHolder viewHolder, int position) {
ItemsAdapter itemAdapter = mList.get(position);
...
if (itemAdapter.isSelected()) {
viewHolder.background.setBackgroundColor(Color.parseColor("#08A467"));
} else {
viewHolder.background.setBackgroundColor(Color.parseColor("#FFFFFF"));
}
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
itemAdapter.setSelected(true);
viewHolder.background.setBackgroundColor(Color.parseColor("#08A467"));
}
});
}
Note that it would be better to define the click listener inside onCreateViewHolder() and to use notifyItemChanged() instead of manually updating the background color, but that's outside the scope of this question.
Since, a Recycler view reuses the views and do not create new views, you need to set default color in onBindViewHolder function.
#Override
public void onBindViewHolder(#NonNull AdapterOccupiedRoomCleaning.ViewHolder viewHolder, int position) {
ItemsAdapter itemAdapter = mList.get(position);
((ViewHolder) viewHolder).setUrduText.setText(itemAdapter.getUrdutext());
((ViewHolder) viewHolder).setEnglishText.setText(itemAdapter.getEnglishText());
((ViewHolder) viewHolder).setCleaningImage.setImageResource(itemAdapter.getImage());
// Add this line
((ViewHolder) viewHolder).background.setBackgroundColor(Color.parseColor("default color"));
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
viewHolder.background.setBackgroundColor(Color.parseColor("#08A467"));
}
});
}
i have a list view in my app.
I want to change it to an recycler view, but even with different tutorials i dont get it.
I was using this: https://www.spreys.com/listview-to-recyclerview/
I failed with the "getView" part here.
Here is my code of the ListActivity and LeagueArrayAdapter.
Thanks for your help.
ListActivity:
public class ListActivity extends AppCompatActivity implements AdapterView.OnItemClickListener {
private ArrayAdapter adapter;
private final int REQUEST_CODE_EDIT = 1;
private static LeagueDAO leagueDAO;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list);
leagueDAO = MainActivity.getLeagueDAO();
List<League> allLeagues1 = leagueDAO.getLeagues();
if (allLeagues1.size() == 0) {
leagueDAO.insert(new League("HVM Landesliga 19/20","https://hvmittelrhein-handball.liga.nu/cgi-bin/WebObjects/nuLigaHBDE.woa/wa/groupPage?championship=MR+19%2F20&group=247189"));
allLeagues1 = leagueDAO.getLeagues();
}
adapter = new LeagueArrayAdapter(this, R.layout.league, allLeagues1);
ListView lv = findViewById(R.id.league_list);
lv.setAdapter(adapter);
lv.setOnItemClickListener(this);
registerForContextMenu(lv);
Button btn_league_add = findViewById(R.id.btn_league_add);
btn_league_add.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(ListActivity.this, EditActivity.class);
startActivity(intent);
}
});
}
#Override
public void onCreateContextMenu(ContextMenu contMenu, View v,
ContextMenu.ContextMenuInfo contextmenuInfo) {
super.onCreateContextMenu(contMenu, v, contextmenuInfo);
getMenuInflater().inflate(R.menu.team_list_context_menu, contMenu);
}
#Override
public boolean onContextItemSelected(MenuItem item) {
AdapterView.AdapterContextMenuInfo acmi=
(AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
League league = (League)adapter.getItem(acmi.position);
switch (item.getItemId()) {
case R.id.evliconit_edit:
editEntry(league, acmi.position);
return true;
case R.id.evliconit_del:
leagueDAO.delete(league);
adapter.remove(league);
adapter.notifyDataSetChanged();
return true;
default:
return super.onContextItemSelected(item);
}
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
League team = (League)adapter.getItem(position);
editEntry(team, position);
}
private void editEntry(League league, int position) {
Intent intent = new Intent(this, EditActivity.class);
intent.putExtra("team", league);
intent.putExtra("position", position);
startActivityForResult(intent, REQUEST_CODE_EDIT);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
if (requestCode == REQUEST_CODE_EDIT && resultCode == RESULT_OK && intent != null) {
Bundle extras = intent.getExtras();
int position = extras.getInt("position");
League league = (League) adapter.getItem(position);
league.setLeague_name(extras.getString("league_name"));
league.setLeague_url(extras.getString("league_url"));
adapter.notifyDataSetChanged();
}
}
#Override
protected void onRestart() {
super.onRestart();
leagueDAO = MainActivity.getLeagueDAO();
List<League> allLeagues1 = leagueDAO.getLeagues();
adapter = new LeagueArrayAdapter(this, R.layout.league, allLeagues1);
ListView lv = findViewById(R.id.league_list);
lv.setAdapter(adapter);
lv.setOnItemClickListener(this);
registerForContextMenu(lv);
}
LeagueArrayAdapter:
public class LeagueArrayAdapter extends ArrayAdapter<League> {
private List<League> leagues;
private Context context;
private int layout;
public LeagueArrayAdapter(Context context, int layout, List<League> leagues) {
super(context, layout, leagues);
this.context = context;
this.layout = layout;
this.leagues = leagues;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
League league = leagues.get(position);
if (convertView == null)
convertView = LayoutInflater.from(context).inflate(layout, null);
TextView tv_name = convertView.findViewById(R.id.tv_name);
TextView tv_url = convertView.findViewById(R.id.tv_url);
tv_name.setText(league.getLeague_name());
tv_url.setText(league.getLeague_url());
return convertView;
}
}
Update: app crashed when opened the activity
public class ListActivity extends AppCompatActivity implements AdapterView.OnItemClickListener {
private ArrayAdapter adapter;
private final int REQUEST_CODE_EDIT = 1;
private static LeagueDAO leagueDAO;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list);
leagueDAO = MainActivity.getLeagueDAO();
List<League> allLeagues1 = leagueDAO.getLeagues();
if (allLeagues1.size() == 0) {
leagueDAO.insert(new League("HVM Landesliga 19/20","https://hvmittelrhein-handball.liga.nu/cgi-bin/WebObjects/nuLigaHBDE.woa/wa/groupPage?championship=MR+19%2F20&group=247189"));
allLeagues1 = leagueDAO.getLeagues();
}
// adapter = new LeagueArrayAdapter(this, R.layout.league, allLeagues1);
RecyclerView lv = findViewById(R.id.league_list);
lv.setHasFixedSize(true);
lv.setLayoutManager(new LinearLayoutManager(this));
lv.setAdapter(new LeagueArrayAdapter(allLeagues1));
// lv.setOnItemClickListener(this);
registerForContextMenu(lv);
Button btn_league_add = findViewById(R.id.btn_league_add);
btn_league_add.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(ListActivity.this, EditActivity.class);
startActivity(intent);
}
});
}
I reconstructed your ListView Adapter using RecyclerView.Adapter.
onCreateView is called for every visible container on your screen. If your screen can show 10 rows of data RecyclerView makes 11 - 12 containers (ViewHolder)
onBindView updates those containers with new data when you scroll.
MyViewHolder is the object that holds data about every row of data (container)
static class and bind() function inside to avoid any memory leak in your adapter.
We have access to Context in RecyclerView.Adapter using itemView and parent
itemView is the inflated View for each container (ViewHolder).
Initialize your Views inside ViewHolder's constructor so they get assigned once.
public class LeagueArrayAdapter extends RecyclerView.Adapter<LeagueArrayAdapter.MyViewHolder> {
private ArrayList<League> leagues;
public LeagueArrayAdapter(ArrayList<League> leagues) {
this.leagues = leagues;
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return LayoutInflater.from(parent.getContext()).inflate(R.layout.row_league, parent, false);
}
#Override
public void onBindViewHolder(#NonNull MyViewHolder holder, int position) {
holder.bind(leagues.get(position));
}
#Override
public int getItemCount() {
return 0;
}
static class MyViewHolder extends RecyclerView.ViewHolder {
TextView tv_name;
TextView tv_url;
public MyViewHolder(#NonNull View itemView) {
super(itemView);
tv_name = itemView.findViewById(R.id.tv_name);
tv_url = itemView.findViewById(R.id.tv_url);
}
void bind(League league) {
tv_name.setText(league.getLeague_name());
tv_url.setText(league.getLeague_url());
}
}
}
Your Activity:
LinearLayoutManager for a linear layout
GridLayoutManager for a grid layout
setHasFixedSize() enhances your RecyclerView's speed if you are sure the RecyclerView itself won't change width or height.
public class LeagueActivity extends AppCompatActivity {
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.YOUR_ACTIVITY_LAYOUT_ID);
...
RecyclerView recyclerView = findViewById(R.id.YOUR_RECYCLER_VIEW_ID);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(new LeagueArrayAdapter(SEND_YOUR_ARRAY_OF_LEAGUE));
}
}
I suggest checking the Groupie Lbrary, it works with recyclerView and it makes life much easier for you, here is an example of how you can use it (I'm writing the code in kotlin but it shouldn't be that different from java)
first, add those lines to your Build.gradle (app) file
implementation 'com.xwray:groupie:2.3.0'
implementation 'com.xwray:groupie-kotlin-android-extensions:2.3.0'
then inside your activity create an adapter then set the adapter to your recyclerView
val myAdapter = GroupAdapter<ViewHolder>()
recyclerView.adapter = myAdapter
and just like this you set the adapter to your recyclerView, but you have to create "Items" to put inside the recyclerView. you can create an Item like so
class MyItem: Item() {
override fun getLayout() = R.layout.layout_seen
override fun bind(viewHolder: ViewHolder, position: Int){
}
}
in the getLayout method, you return the layout that you to display inside the recyclerView,
you can use the bind method to do any kind of modifications we want to apply to our layout that we are displaying.
lastly, we can add our items to the adapter this way
myAdapter.add(MyItem())
myAdapter.notifyDataSetChanged()
for more details check the library, in here I just explained how you can simply add an item to your RecyclerView
I need some help for a summer project
This is my Events fragment
This is my MyList fragment
I'm using a RecyclerView+Cardview to display the Events. The idea is that the user can click the big plus on the right side of each card, and the card would be displayed in the MyList fragment. I would like to ask if it's possible to transfer a card directly from one fragment to another? Also, both fragments are contained within the same activity, which makes it a little trickier(I haven't found any available solutions).
If that is not possible, another way is to transfer the reference type object contained in the CardView to the MyList fragment. However, this is even less straightforward. This is because the button is inflated in the adapter, but there is no reference type object created here. I have seen many tutorials on using the Parcelable interface, however, I don't know how to implement it here when I'm unable to even create the object in the adapter. The reference object is created in another activity and stored in Firebase before it is read and displayed.
I'm going to attach my EventsAdapter.java and EventsItem.java and EventsFragment.java code below, but please let me know if I should include more code to describe the problem.
Thanks for reading my very long post!!
public class EventsAdapter extends RecyclerView.Adapter<EventsAdapter.EventsViewHolder> implements Filterable {
private ArrayList<EventsItem> mEventsList;
private ArrayList<EventsItem> mEventsListFull;
private EventsAdapter.OnItemClickListener mListener;
private Context mContext;
private DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.UK);
public interface OnItemClickListener {
void onItemClick(int position);
}
//the ViewHolder holds the content of the card
public static class EventsViewHolder extends RecyclerView.ViewHolder {
public ImageView mImageView;
public ImageView mAddButton;
public TextView mTextView1;
public TextView mTextView2;
public TextView mTextView3;
public TextView mTextView4;
public TextView mTextView5;
public EventsViewHolder(Context context, View itemView, final EventsAdapter.OnItemClickListener listener) {
super(itemView);
final Context context1 = context;
mImageView = itemView.findViewById(R.id.imageView);
mAddButton = itemView.findViewById(R.id.image_add);
mTextView1 = itemView.findViewById(R.id.title);
mTextView2 = itemView.findViewById(R.id.event_description);
mTextView3 = itemView.findViewById(R.id.date);
mTextView4 = itemView.findViewById(R.id.location);
mTextView5 = itemView.findViewById(R.id.time);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener != null) {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
listener.onItemClick(position);
}
}
}
});
mAddButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String str1 = mTextView1.getText().toString();
String str2 = mTextView2.getText().toString();
String str3 = mTextView3.getText().toString();
String str4 = mTextView4.getText().toString();
String str5 = mTextView5.getText().toString();
Bundle bundle = new Bundle();
bundle.putString("title", str1);
bundle.putString("event description", str2);
bundle.putString("date", str3);
bundle.putString("location", str4);
bundle.putString("time", str5);
MylistFragment mlf = new MylistFragment();
mlf.setArguments(bundle);
}
});
}
}
//Constructor for EventsAdapter class. This ArrayList contains the
//complete list of items that we want to add to the View.
public EventsAdapter(Context context, ArrayList<EventsItem> EventsList) {
mEventsList = EventsList;
mContext = context;
mEventsListFull = new ArrayList<>(EventsList); // copy of EventsList for SearchView
}
//inflate the items in a EventsViewHolder
#NonNull
#Override
public EventsAdapter.EventsViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.event_item, parent, false);
EventsAdapter.EventsViewHolder evh = new EventsAdapter.EventsViewHolder(mContext, v, mListener);
return evh;
}
#Override
public void onBindViewHolder(#NonNull EventsAdapter.EventsViewHolder holder, int position) {
EventsItem currentItem = mEventsList.get(position);
holder.mImageView.setImageResource(currentItem.getProfilePicture());
holder.mTextView1.setText(currentItem.getTitle());
holder.mTextView2.setText(currentItem.getDescription());
holder.mTextView3.setText(df.format(currentItem.getDateInfo()));
holder.mTextView4.setText(currentItem.getLocationInfo());
holder.mTextView5.setText(currentItem.getTimeInfo());
}
#Override
public int getItemCount() {
return mEventsList.size();
}
public class EventsItem implements Occasion, Parcelable {
//fields removed for brevity
//constructor removed for brevity
}
public EventsItem() {
}
public EventsItem(Parcel in) {
profilePicture = in.readInt();
timeInfo = in.readString();
hourOfDay = in.readInt();
minute = in.readInt();
locationInfo = in.readString();
title = in.readString();
description = in.readString();
}
public static final Creator<EventsItem> CREATOR = new Creator<EventsItem>() {
#Override
public EventsItem createFromParcel(Parcel in) {
return new EventsItem(in);
}
#Override
public EventsItem[] newArray(int size) {
return new EventsItem[size];
}
};
//getter methods have been removed for brevity
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(profilePicture);
dest.writeString(timeInfo);
dest.writeString(locationInfo);
dest.writeString(title);
dest.writeString(description);
dest.writeString(df.format(dateInfo));
dest.writeInt(hourOfDay);
dest.writeInt(minute);
}
}
public class EventsFragment extends Fragment {
ArrayList<EventsItem> EventsItemList;
FirebaseDatabase mDatabase;
DatabaseReference mDatabaseReference;
ValueEventListener mValueEventListener;
private RecyclerView mRecyclerView;
private RecyclerView.LayoutManager mLayoutManager;
private EventsAdapter mAdapter;
private View rootView;
public FloatingActionButton floatingActionButton;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_events, container, false);
mDatabase = FirebaseDatabase.getInstance();
mDatabaseReference = mDatabase.getReference().child("Events");
createEventsList();
buildRecyclerView();
floatingActionButton = rootView.findViewById(R.id.fab);
floatingActionButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(getActivity(), EventsAdder.class);
startActivity(intent);
}
});
mValueEventListener = new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
EventsItemList.add(snapshot.getValue(EventsItem.class));
}
EventsAdapter eventsAdapter = new EventsAdapter(getActivity(), EventsItemList);
mRecyclerView.setAdapter(eventsAdapter);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
};
mDatabaseReference.addValueEventListener(mValueEventListener);
setHasOptionsMenu(true);
Toolbar toolbar = rootView.findViewById(R.id.events_toolbar);
AppCompatActivity activity = (AppCompatActivity) getActivity();
activity.setSupportActionBar(toolbar);
return rootView;
}
public void createEventsList() {
EventsItemList = new ArrayList<>();
}
public void buildRecyclerView() {
mRecyclerView = rootView.findViewById(R.id.recyclerview);
mLayoutManager = new LinearLayoutManager(getContext());
mAdapter = new EventsAdapter(getActivity(), EventsItemList);
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
}
}
If you would like to see the same CardView within the MyListFragment, you could have the MyListFragment contain a RecyclerView, and reuse the same EventsAdapter and EventsViewHolder. The only difference is that rather than populating the adapter with all the children of the "Events" from your database, you would only populate it with the single Event that you want.
Also, since you have made your Event class implement parcelable, you do not need to manually create the bundle when clicking the plus button.
I am assuming you have a single Activity, and you simply want to replace the EventsFragment with the MyListFragment. Checkout the docs for replacing one fragment with another.
Step 1:
Extend your onItemClickListener to look like:
public interface OnItemClickListener {
void onItemClick(int position);
void onPlusButtonClick(int position);
}
and adjust the code in your EventsViewHolder constructor to look like this when the plus button is clicked:
mAddButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener != null) {
// no need to manually create the bundle here
// you already have all the information you need
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
listener.onPlusButtonClick(position);
}
}
}
});
Step 2:
Implement our new method onPlusButtonClick. As per our discussion in the comments, it seems you do not implement this interface anywhere. You can implement it inside the constructor to your EventsAdapter:
public EventsAdapter(Context context, ArrayList<EventsItem> EventsList) {
mEventsList = EventsList;
mContext = context;
mEventsListFull = new ArrayList<>(EventsList); // copy of EventsList for SearchView
mListener = new OnItemClickListener() {
#Override
public void onItemClick() {
// handle clicking the entire view holder
// NOTE: inside your EventsViewHolder, it looks like you call this method on the entire itemView. This could 'swallow' the click on the plus button. You may need to adjust your code to handle this.
}
#Override
public void onPlusButtonClick(int position) {
MyListFragment myListFragment = new MyListFragment();
Event event = mEventsList.get(position);
Bundle bundle = new Bundle();
bundle.putExtra("event", event); // this will work due to implementing parcelable
myListFragment.setArguments(bundle);
// use mContext since im assuming we areinside adapter
// if in an Activity, no need to use context to get the fragment manager
FragmentTransaction transaction = mContext.getSupportFragmentManager().beginTransaction();
// Replace the EventsFragment with the MyListFragment
// and add the transaction to the back stack so the user can navigate back
transaction.replace(R.id.fragment_container, myListFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
}
}
}
Step 3:
Inside your MyListFragments onCreateView() method:
#Override
public View onCreateView (
LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState
) {
Bundle bundle = getArguments();
Event event = bundle.getExtra("event"); // again, will work due to implementing parcelable
// from here you should bind to a recycler view, and you can even reuse your adapter like so:
List<EventsItem> singleEventList = new List<EventsItem>();
singleEventList.add(event);
EventsAdapter adapter = new EventsAdapter(getActivity(), singleEventList);
// be sure to inflate and return your view here...
}
and you should be good to go!
I have left out bits of code here and there for simplicity.. but I hope this is understandable.
As a side note.. in your firebase database listener, it is bad practice to create a new EventsAdapter every single time your data is updated. Instead, you should update the data in the adapter with the new values. Do this by creating a public method inside the adapter such as replaceEvents(List<EventsItem> newEvents), and inside, replace mEventsList with the new events, then call notifyDataSetChanged().
I've made a image slider with help of viewpager and picasso, now i want to add next, prev button on the image, how can i do that?
I saw different answers of this but all of them are showing error
This is main activity where image slider is shown:
public class MainActivity extends AppCompatActivity {
private int[] imageUrls = new int[]{
R.drawable.after_cookie,
R.drawable.before_cookie
};
private WebBackForwardList viewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewPager viewPager = findViewById(R.id.view_pager);
ViewPageAdapter adapter = new ViewPageAdapter(this, imageUrls);
viewPager.setAdapter(adapter);
}
}
This is ViewPageAdapter:
public class ViewPageAdapter extends PagerAdapter {
private Context context;
private int[] imageUrls;
ViewPageAdapter(Context context, int[] imageUrls) {
this.context = context;
this.imageUrls = imageUrls;
}
#Override
public int getCount() {
return imageUrls.length;
}
#Override
public boolean isViewFromObject(#NonNull View view, #NonNull Object object) {
return view == object;
}
#NonNull
#Override
public Object instantiateItem(#NonNull ViewGroup container, int position) {
ImageView imageView = new ImageView(context);
Picasso.get()
.load(imageUrls[position])
.fit()
.centerCrop()
.into(imageView);
container.addView(imageView);
return imageView;
}
#Override
public void destroyItem(#NonNull ViewGroup container, int position, #NonNull Object object) {
container.removeView((View) object);
}
}
add this method to your code
private int getItem(int i) {
return viewPager.getCurrentItem() + i;
}
then use this for next button
Button NextButton = (Button)findViewById(R.id.button1);
yourButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
viewPager.setCurrentItem(getItem(+1), true); //getItem(+1) for next
}
});
and use this for the previous button
Button PreviousButton = (Button)findViewById(R.id.button2);
PreviousButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
viewPager.setCurrentItem(getItem(-1), true); //getItem(-1) for previous
}
});
it will work fine ;)
I am having problems updating my RecyclerView with new data. If I press a confirmation button on a CardView in the first tab, the card should get added to the second tab but it won't update it there until I rotate the screen. I get the data for the card from reading a text file. Please advise me how to call the notifyDataSetChange method after I have added the new data to my text file. I have tried everything and all I get is NullPointerExceptions. The RecyclerViews are in fragments and I use FragementStatePagerAdapter.
I'll put some of my classes here. Ask if you need more information.
RecyclerViewAdapter.java
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewHolder> {
private List<String> mListTitle;
private List<String> mListDesc;
private List<String> mListPoints;
private List<String> mListDates;
private String fragment_tag;
public RecyclerViewAdapter() {
}
public RecyclerViewAdapter(List<List<String>> super_list, String tag) {
this.mListTitle = super_list.get(0);
this.mListDesc = super_list.get(1);
this.mListPoints = super_list.get(2);
this.mListDates = super_list.get(3);
fragment_tag = tag;
}
#Override
public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
return new RecyclerViewHolder(inflater, parent, fragment_tag);
}
#Override
public void onBindViewHolder(RecyclerViewHolder holder, int position) {
holder.mTitleText.setText(mListTitle.get(position));
holder.mDescText.setText(mListDesc.get(position));
holder.mPointsText.setText(mListPoints.get(position));
if (fragment_tag.equals("completed")) {
holder.mDateText.setText(mListDates.get(position));
}
}
#Override
public int getItemCount() {
return mListTitle.size();
}
}
class RecyclerViewHolder extends RecyclerView.ViewHolder {
RecyclerView recyclerView;
RecyclerViewAdapter mAdapter;
public TextView mTitleText, mDescText, mDateText, mPointsText, popupTitle;
public Button mConfButton, popCancelBtn, popAcceptBtn;
public RecyclerViewHolder(View itemView) {
super(itemView);
}
public RecyclerViewHolder(final LayoutInflater inflater, final ViewGroup container, String tag) {
// Inflating the card layout depending on the tag parameter.
super(inflater.inflate
((tag.equals("challenges")) ? R.layout.card_view_chall : R.layout.card_view_comp, container,
false));
mTitleText = itemView.findViewById(R.id.title_holder);
mDescText = itemView.findViewById(R.id.desc_holder);
mPointsText = itemView.findViewById(R.id.points_holder);
mDateText = itemView.findViewById(R.id.date_holder);
if (tag.equals("challenges")) {
mConfButton = itemView.findViewById(R.id.card_conf_button);
mConfButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Setting the layout inflater for popup window.
LayoutInflater pInflater = (LayoutInflater) itemView.getContext().getSystemService(LAYOUT_INFLATER_SERVICE);
ViewGroup container1 = (ViewGroup) pInflater.inflate(R.layout.confirmation_popup, null);
final PopupWindow popupWindow = new PopupWindow(container1, 700, 600, true);
popupTitle = container1.findViewById(R.id.popuptext);
popAcceptBtn = container1.findViewById(R.id.accept_button);
popCancelBtn = container1.findViewById(R.id.cancel_button);
popupTitle.setText(mTitleText.getText().toString());
// Dismisses the popup window
popCancelBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
popupWindow.dismiss();
}
});
// Click listener for dialog accept button.
popAcceptBtn.setOnClickListener(new View.OnClickListener() {
String date;
#Override
public void onClick(View view) {
List<String> list = new ArrayList<>();
list.add(mTitleText.getText().toString());
list.add(mDescText.getText().toString());
list.add(mPointsText.getText().toString());
list.add(date = new SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()).format(new Date()));
// Saving data from current card into the completed challenges list.
TempDataReader reader = new TempDataReader(itemView.getContext());
new TempDataReader(itemView.getContext()).saveFile(list);
// I want to notify the dataset change here if possible!
popupWindow.dismiss();
}
});
popupWindow.showAtLocation(itemView, Gravity.CENTER, 25, 100);
}
});
}
}
}
SectionsPagerAdapter.java
public class SectionsPagerAdapter extends FragmentStatePagerAdapter{
private ViewPager viewPager;
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public void addFragment(Fragment fragment, String title){
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
#Override
public void notifyDataSetChanged() {
super.notifyDataSetChanged();
}
}
CompletedFragment.java
public class CompletedFragment extends Fragment {
RecyclerView recyclerView;
RecyclerViewAdapter adapter;
public Fragment newInstance() {
return new CompletedFragment();
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.completed_fragment, container, false);
recyclerView = view.findViewById(R.id.completed_frag);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
TempDataReader reader = new TempDataReader(getActivity());
List<List<String>> super_list = reader.readCompFile();
if(super_list == null || super_list.size() < 1){
return null;
} else{
adapter = new RecyclerViewAdapter(super_list,"completed");
recyclerView.setAdapter(adapter);
return view;
}
}
}
EDIT:
Added the code for the second fragment, which is the one that should be updated after the onClick at RecyclerViewHolder-class.
You have to add a function in your adapter for adding data:
public void addData(String title, String desc, String point, String date) {
this.mListTitle.add(title);
this.mListDesc.add(desc);
this.mListPoints.add(point);
this.mListDates.add(date);
notifyDataSetChanged();
}
If you want to enable animations call notifyItemInserted() instead of notifyDataSetChanged();
It is important that you add a String to every list because in your onBindViewHolder() you get the item to display from every list with list.get(position). Otherwise you'll get a IndexOutOfBoundsException.
You can create an interface and use as a callback. Send it as a parameter of the RecyclerViewAdapter and then to your RecyclerViewHolder. When the item should be added you call the callback that will get you back to your fragment. There you can read the file again and call notifyDataSetChanged.
I know i explain pretty bad so i will try to change your code so that it does what i said:
this will be your RecyclerViewAdapter:
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewHolder> {
private List<String> mListTitle;
private List<String> mListDesc;
private List<String> mListPoints;
private List<String> mListDates;
private String fragment_tag;
private Runnable callback;
public RecyclerViewAdapter() {
}
public RecyclerViewAdapter(List<List<String>> super_list, String tag, Runnable callBack) {
//add the callback here(Runnable) and save it into a local variable
this.callback=callback;
this.mListTitle = super_list.get(0);
this.mListDesc = super_list.get(1);
this.mListPoints = super_list.get(2);
this.mListDates = super_list.get(3);
fragment_tag = tag;
}
#Override
public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
return new RecyclerViewHolder(inflater, parent, fragment_tag, callback);
//send the callback to your viewHolder
}
#Override
public void onBindViewHolder(RecyclerViewHolder holder, int position) {
holder.mTitleText.setText(mListTitle.get(position));
holder.mDescText.setText(mListDesc.get(position));
holder.mPointsText.setText(mListPoints.get(position));
if (fragment_tag.equals("completed")) {
holder.mDateText.setText(mListDates.get(position));
}
}
#Override
public int getItemCount() {
return mListTitle.size();
}
}
class RecyclerViewHolder extends RecyclerView.ViewHolder {
RecyclerView recyclerView;
RecyclerViewAdapter mAdapter;
public TextView mTitleText, mDescText, mDateText, mPointsText, popupTitle;
public Button mConfButton, popCancelBtn, popAcceptBtn;
public RecyclerViewHolder(View itemView) {
super(itemView);
}
public RecyclerViewHolder(final LayoutInflater inflater, final ViewGroup container, String tag, Runnable callback) {
//ADD the callback to the parameters list here
// Inflating the card layout depending on the tag parameter.
super(inflater.inflate
((tag.equals("challenges")) ? R.layout.card_view_chall : R.layout.card_view_comp, container,
false));
mTitleText = itemView.findViewById(R.id.title_holder);
mDescText = itemView.findViewById(R.id.desc_holder);
mPointsText = itemView.findViewById(R.id.points_holder);
mDateText = itemView.findViewById(R.id.date_holder);
if (tag.equals("challenges")) {
mConfButton = itemView.findViewById(R.id.card_conf_button);
mConfButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Setting the layout inflater for popup window.
LayoutInflater pInflater = (LayoutInflater) itemView.getContext().getSystemService(LAYOUT_INFLATER_SERVICE);
ViewGroup container1 = (ViewGroup) pInflater.inflate(R.layout.confirmation_popup, null);
final PopupWindow popupWindow = new PopupWindow(container1, 700, 600, true);
popupTitle = container1.findViewById(R.id.popuptext);
popAcceptBtn = container1.findViewById(R.id.accept_button);
popCancelBtn = container1.findViewById(R.id.cancel_button);
popupTitle.setText(mTitleText.getText().toString());
// Dismisses the popup window
popCancelBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
popupWindow.dismiss();
}
});
// Click listener for dialog accept button.
popAcceptBtn.setOnClickListener(new View.OnClickListener() {
String date;
#Override
public void onClick(View view) {
List<String> list = new ArrayList<>();
list.add(mTitleText.getText().toString());
list.add(mDescText.getText().toString());
list.add(mPointsText.getText().toString());
list.add(date = new SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()).format(new Date()));
// Saving data from current card into the completed challenges list.
TempDataReader reader = new TempDataReader(itemView.getContext());
new TempDataReader(itemView.getContext()).saveFile(list);
// I want to notify the dataset change here if possible!
//call the callback
callback.run();
popupWindow.dismiss();
}
});
popupWindow.showAtLocation(itemView, Gravity.CENTER, 25, 100);
}
});
}
}
}
And this will be your fragment:
public class CompletedFragment extends Fragment {
RecyclerView recyclerView;
RecyclerViewAdapter adapter;
public Fragment newInstance() {
return new CompletedFragment();
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.completed_fragment, container, false);
recyclerView = view.findViewById(R.id.completed_frag);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
TempDataReader reader = new TempDataReader(getActivity());
List<List<String>> super_list = reader.readCompFile();
if(super_list == null || super_list.size() < 1){
return null;
} else{
adapter = new RecyclerViewAdapter(super_list,"completed", new Runnable() {
#Override
public void run() {
//here read the list again and call notifyDataSetChanged on your recycler
}
});
);
recyclerView.setAdapter(adapter);
return view;
}
}
}
Hope it helps and it works for you. If i did anything wrong, let me know, i can't run the code right now so...
edited, i forgot to add code in the callback