I am using the FirebaseRecyclerAdapter to populate views dynamically as data is added to Firebase.
However, I also want to modify the views that the RecyclerView populates as data changes in Firebase. For instance, I have a counter on each view that is populated, and as people vote on that topic, I want the counter to increase:
My idea is to set a tag to each view that is populated in the RecyclerView, find a way to get the current views that are on the screen, and then update those views dynamically. I am kind of lost how I would proceed, but here is my PollHolder:
public static class PollHolder extends RecyclerView.ViewHolder {
TextView mPollQuestion;
TextView mVoteCount;
ImageView mPollImage;
View mView;
String mTag;
public PollHolder(View itemView) {
super(itemView);
mPollQuestion = (TextView) itemView.findViewById(R.id.latest_item_question);
mPollImage = (ImageView) itemView.findViewById(R.id.pollThumbNailImage);
mVoteCount = (TextView) itemView.findViewById(R.id.latest_item_poll_count);
this.mView = itemView;
}
public void setVoteCount (String voteCount){
mVoteCount.setText(voteCount);
}
public void setTag(String tag){
this.mTag = tag;
}
public View getViewByTag(String tag){
return mView;
}
}
Here are the views in the RecyclerView. I want the counter in the lower right corner to update, but again I do not want to completely recreate/repopulate the RecyclerView.
when you insert new get the position of that row.Then you can refresh specific row by using
notifyItemInserted (int position);
Its not refresh or recreate all data in RecyclerView but its alternate the count of list and refresh the particular position.
Representations of other existing items in the data set are still considered up to date and will not be rebound, though their positions may be altered.
More details refer RecyclerView.Adapter
Related
So I am trying to create a challenge game where you can have 2 options to pick from, I have 2 card views setup in a recycler view setup, how would I change the values in them to get a new challenge with the click of a button from the main activity if a user wanted a new challenge?
I am fetching the data from each battle at random using an SQLite database.
My onBindViewHolder
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
SQLiteDatabase sqLiteDatabase = faceMashDatabaseHelper.getReadableDatabase();
cursor = sqLiteDatabase.query("images", new String[]{"id","filename","name"},null,null,null,null,null);
MyViewHolder myViewHolder = (MyViewHolder) holder;
int position1 = (int)(Math.random()*(faceMashDatabaseHelper.getCount()-0+1)+0);
cursor.moveToPosition(position1);
String filename = cursor.getString(cursor.getColumnIndex("filename"));
String name = cursor.getString(cursor.getColumnIndex("name"));
CardView cardView = myViewHolder.getCardView();
ImageView imageView = (ImageView) cardView.findViewById(R.id.imageView);
TextView nameView = (TextView) cardView.findViewById(R.id.nameView);
nameView.setText(name);
File file = context.getFileStreamPath(filename);
if(file.exists()){
Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
imageView.setImageBitmap(bitmap);
}
cardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String name = nameView.getText().toString();
listener.onClick(position,name);
}
}); //This on click is for the card views themselves.
}
My onClick at the current moment, I'm using a toolbar option
case R.id.newbattle:
faceMashAdapter.notifyDataSetChanged();
First of all, you should never do heavy work in onBindViewHolder since it will be called every time your View is recreated after it was recycled (because it was unused).
You should query your Database outside of the Adapter instead and occupy a List with your queried data. Your List should have as many entries as your RecyclerView has entries. Then you can use the position parameter in onBindViewHolder to always get the correct data for the entry (list.get(position)).
This way you can just change the content of your List and notify the Adapter which items have changed via notifyItemChanged (or if all items should be refreshed, use notifyDataSetChanged). That way the content of the Adapter is refreshed.
So what you should do in your onClick is update the content of your List and notify the Adapter.
I want to add a feature on my project where if the user clicks one of the items on the listView then a checkbox would appear allowing the user to delete 1 or many items at once. Similar to Samsung Notes when you want to delete notes and or folders, etc. However, this concept is completely foreign to me and currently, I don't know where to begin to start this or what topic/resource/sample code I should look for. Also, I have a custom Array Adapter class that I used to order to work with my ListView but it came to my knowledge that you only need 1 array adapter class to make this work which made me confused since I don't know where to begin to manipulate it even further. Any help would be amazing!
Here is my Array Adapter that I have at the moment
//want to create our own custom ArrayAdapter. Going to extends the base class ArrayAdapter and hold our
//Word object
public class WordAdapter extends ArrayAdapter<WordFolder> {
//constructor - it takes the context and the list of words
WordAdapter(Context context, ArrayList<WordFolder> word){
super(context, 0, word);
}
#Override
public View getView(int position, View convertView, ViewGroup parent){
View listItemView = convertView;
if(listItemView == null){
listItemView = LayoutInflater.from(getContext()).inflate(R.layout.folder_view, parent, false);
}
//Getting the current word
WordFolder currentWord = getItem(position);
//making the 3 text view to match our word_folder.xml
TextView date_created = (TextView) listItemView.findViewById(R.id.date_created);
TextView title = (TextView) listItemView.findViewById(R.id.title);
TextView desc = (TextView) listItemView.findViewById(R.id.desc);
//using the setText to get the text and set it in the textView
date_created.setText(currentWord.getDateCreated());
title.setText(currentWord.getTitle());
desc.setText(currentWord.getTitleDesc());
return listItemView;
}
}```
In R.layout.folder_view add one and make it invisible or gone. OnLongClick make them Visible.
I already created this with custom adapter in another project, but I didn't use fragments. I now have a project using fragments, and am displaying the listview in a fragment. I don't know or am able to find exactly what rules and what classes/java files I need for this to work in a fragment.
Every example on the internet I've used develops an error in some way, and since I don't understand every aspect of how this is done I can't fix it on my own.
In my previous project, I did this (CalculationsActivity.java):
public class CalculationsActivity extends AppCompatActivity implements Serializable {
//content of my class
}
class CustomAdapter extends BaseAdapter {
#Override
public int getCount() {
return arrayLi.size();
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
view = getLayoutInflater().inflate(R.layout.customlayout, null);
ImageView imageView = (ImageView) view.findViewById(R.id.imageView);
TextView content = (TextView) view.findViewById(R.id.content);
TextView date = (TextView) view.findViewById(R.id.date);
imageView.setImageResource(R.drawable.calcer);
String[] convertedArrLi = arrayLi.toArray(new String[arrayLi.size()]);
String[] convertedDates = dates.toArray(new String[dates.size()]);
content.setText(convertedArrLi[i]);
date.setText(convertedDates[i]);
return view;
}
}
And from that I set an adapter to my listview. This class was in the same java file as the activity that the listview was displayed in. If I do this in my fragment, I get a bunch of red lines. getLayoutInflater() and variables from my other class above it will be red.
As I understand so far you need MainActivity.java, MyFragment.java and Adapter.java. To make your listview work with your array you need to set an adapter including the current activity and the array you want to use. If someone can explain what files I actually need and how they work together (send info to each other and start one another), I would appreciate it.
Note: I have to use a custom adapter.
You can use your custom adapter in activity and in fragment, there is no difference. Can you provide screenshot of your bunch of red lines?
Also your question is incorrect: "what files do I need?". You need classes, first class for activity or fragment to create/declare/initialize second class (custom adapter) and fill it with data.
I'm new to android, but have a good JavaFX experience. I'm trying to create a custom view that i can reuse, but having a hard time figuring out the correct way to do it.
In javafx i could achieve this by: Creating a separate fxml file defining the layout of the custom view, then create a controller class linked to the fxml file, in that class, i'd have a method to retrieve the data model of the controller and use it to fill in the labels, etc.
The custom view i want would be
Constrained Layout
TextView (constrained to right anchor)
Round TextView (constrained to left anchor)
What is the best way to do this in android? Also, Is it possible to achieve this with a RecyclerView? If yes, how can i use a custom view for each item and set its data?
The question is broad. You may need additional research on creating views
Create a recyclerview in the main.xml,
a separate file with an item view.
You have 3 views in your item view - white background with margins (linearlayout?), right textView, and left textview.
The left textview should have android:background="drawable/round_shape" and round_shape.xml defined in your drawables folder. Everything is done in 3 xml files, main.xml for recyclerview, item.xml, round_background.xml. Then, the recyclerview adapter to bind the textviews with your array, and recyclerview initialization
A typical RV adaptor
public class MyRV extends RecyclerView.Adapter<MyRV.ViewHolder> {
private List<MyModelItemWith2Strings> mDataSet; // You may need to setup an array,
// with 2 String objects - for the right and left textviews
// Use an array of class with 2 elements rather than <String>, e.g. List<MyModelItemWith2Strings>
// pass your model here
// this setData will be used to provide the contents for the textviews
void setData(List< /* set your 2 string class here*/ > dataSet) {
mDataSet = dataSet;
}
static class ViewHolder extends RecyclerView.ViewHolder {
// Here you bind item TV's
// first you declare textviews that you will use to fill with data
// Add any other item views you will need to fill in
public TextView tv;
public TextView tv2;
public ViewHolder(LinearLayout v) {
super(v);
// Bind itemview views here. Put R.id.tv from your itemview.xml
tv = v.findViewById(R.id.....);
tv2 = v...
}
}
// Add your itemview layout here
#Override
public MyRV.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LinearLayout v = (LinearLayout) LayoutInflater.from(parent.getContext())
.inflate(/***R.layout.item_view***/, parent, false);
ViewHolder vh = new ViewHolder(v);
return vh;
}
#Override
public void onBindViewHolder( MyRV.ViewHolder h, int position) {
// get content from your model (the above list) and fill in the the itemview textviews
String a= mDataSet.get(position).getItem1();
String b = mDataSet.get(position). getItem2();
...
h.tv.setText(a);
// set clickers if you want to. The clicker class is below.
h.tv.setOnClickListener(new Click(position));
h.tv2.setText(...)
}
// This is obligatory to pass for your RV to initialize. It won't work if you don' t tell Android how to count your array soze
#Override
public int getItemCount() {
return mDataSet.size();
}
// These are my implementation of clickers. I prefer to put them in the nested class of the adapter.
private class Click implements OnClickListener {
private int pos;
Click(int position) {
pos = position;
}
#Override
public void onClick(View p1) {
// get data from your array on click
mDataSet.get(pos);
// Use pos as position on the array, mData.get(pos)
}
}
}
Then, in your main class set a recyclerview
RecyclerView rv = (RecyclerView) findViewById(R.id.rv_In_Main_Xml);
// just additional tunings.
rv.setHasFixedSize(true);
rv.setLayoutManager(new LinearLayoutManager(context)); // <- context = this, if you are in the Main activity
Then set the adapter
MyRV rva = new MyRV();
rva.setData(myArray_with_2_string_objects_to_fill_tvs);
rv.setAdaptor(rva);
And your recycler view gets filled with data
I have created an app that contains a viewPager inside the mainActivity, this viewPager contains 5 fragments, of which 4 are recyclerViews and one is a normal linearLayout containing some text...
Here is a screenshot of the app, not all tabs in the tablayout are visible:
Now, as you might have seen already, there isn't much space in the viewPager for the user to see anything, so they have to scroll too much to view things in the recylerView. I want to modify my app so that when the user tries to scroll inside the recyclerView, the visible part of the mainActivity is scrolled down till the recyclerView occupies the entire page and then the recyclerView begins to scroll normally.
Can someone please help me implement this type of scroll feature into my app. You can just check out this app for a reference to what I'm saying. Just open up any movie or tvSeries and then try scrolling, the mainActivity gets scrolled first and then the rest of the layout.... Can someone please help. I've already tried the solutions on stackOverflow and many of them don't work, I also tried to google for a solution, but didn't get anything useful....
Here is the code for my adapter:
public class cardViewAdapterCreditsCast extends RecyclerView.Adapter<cardViewAdapterCreditsCast.ViewHolder> {
private Context context;
private List<creditsModel> creditsModels;
public cardViewAdapterCreditsCast(Context context, List<creditsModel> creditsModels) {
this.context = context;
this.creditsModels = creditsModels;
}
#Override
public cardViewAdapterCreditsCast.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.new_cast_row, parent, false);
return new cardViewAdapterCreditsCast.ViewHolder(view);
}
#Override
public void onBindViewHolder(cardViewAdapterCreditsCast.ViewHolder holder, int position) {
final creditsModel creditsModel = creditsModels.get(position);
int tempNumber = holder.celebImage.getWidth();
holder.celebImage.setMinimumHeight(tempNumber);
holder.celebImage.setMaxHeight(tempNumber + 1);
String imagePath = "https://image.tmdb.org/t/p/w500" + creditsModel.getProfilePath();
holder.starringAs.setText(creditsModel.getCharacter());
holder.celebName.setText(creditsModel.getActorName());
if (creditsModel.getProfilePath() != null) {
Picasso.with(context).load(imagePath).transform(new CircleTransform()).into(holder.celebImage);
} else
holder.celebImage.setBackgroundResource(R.drawable.not_found);
}
#Override
public int getItemCount() {
return creditsModels.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public ImageView celebImage;
public TextView celebName;
public TextView starringAs;
private LinearLayout linearLayout;
public ViewHolder(View itemView) {
super(itemView);
linearLayout = (LinearLayout) itemView.findViewById(R.id.castRowMainLinearLayout);
celebImage = (ImageView) itemView.findViewById(R.id.castRowImage);
celebName = (TextView) itemView.findViewById(R.id.castRowName);
starringAs = (TextView) itemView.findViewById(R.id.castRowAppearance);
}
}
}
Use nested Scrollview if there are more than one scrollview or recyclerview.
You can use a CoordinatorLayout to implement this easily.
Example, http://saulmm.github.io/mastering-coordinator
Documentation, https://developer.android.com/reference/android/support/design/widget/CoordinatorLayout.html