On scrolling the RecyclerView the data inside the TextView changes even though the data in the array logtime.get(i).getTime() does not change.it changes only when we place the data inside textview which is generating dynamically.
public void onBindViewHolder(PunchCardViewHolder holder, int position) {
PunchCardReport punchCardReport = punchCardReports.get(position);
holder.sNumber.setText(punchCardReport.getmSNumber());
holder.logDate.setText(punchCardReport.getmLogDate());
StringTokenizer stringTokenizer = new StringTokenizer(punchCardReport.getmLogTime(), ",");
List<LogTime> logtime = punchCardReport.getmLogTimeList();
for (int i = 0; i < logtime.size(); i++) {
Log.d(TAG, "onBindViewHolder: "+logtime.get(i).getTime());
}
LinearLayout.LayoutParams dim = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
for (int i = 0; i < logtime.size(); i++) {
TextView textView=new TextView(mContext);
textView.setLayoutParams(dim);
textView.setText(logtime.get(i).getTime());//the problem is here when we put data inside textview
holder.logTime.addView(textView);
}
}
#Override
public int getItemCount () {
return punchCardReports.size();
}
Your design is completely wrong. You are creating new TextViews on every call to onBindViewHolder() which means when you scroll back to a view a fresh list of TextViews are created, so now you have two sets of TextViews one from last call and one from now (Keep scrolling and there will be more extra TextViews attached).
Creating new Views should be done in onCreateViewHolder(). The reason you are getting this behavior could be because RecyclerView uses Scrapped Views, which means that it reuses the Views created earlier. Thus enhancing performance (because no new memory allocations are required). If you are looking for a Nested RecyclerView then do that instead.
You can add following code in onBindViewHolder.
if(holder.logTime.getChildCount()>0){
holder.logTime.removeAllViews();
}
for (int i = 0; i < logtime.size(); i++) {
TextView textView=new TextView(mContext);
textView.setLayoutParams(dim);
textView.setText(logtime.get(i).getTime());
//the problem is here when we put data inside textview
holder.logTime.addView(textView);
}
Try to Put this line in starting of onbindViewHolder.
holder.setIsRecyclable(false);
Or, you can put your TextView inside XML file. There is no need to create dynamic textview inside Onbinder.
You just add holder.setIsRecyclable(false); inside method onBindViewHolder in your Adapter
Related
I have a list of data to be displayed in a recycler view and that is working fine. Now I have another dynamic list of data to be displayed inside the parent recycler-view. So I tried using another recycler-view inside the parent recycler-view, that is not working fine. It will be good if I get some idea of using recycler-view inside another one. Thanks in advance..!
I have illustrated my problem with an example:
For eg: I have a parent recyclerView with five linearLayout and I have created a child recyclerView inside the Linearlayout with visibility GONE. Now when I click the first Linearlayout I am changing the visibility of child recyclerView for the first Linearlayout to VISIBLE and attaching a separate view to it and same concept for all the other Linearlayouts. What happens is when I click first, second, third and fourth linearLayout the child recyclerView is not displaying date which I pass to it, all those first, sec, third and fourth data are accumulated and displayed in the last (i.e) inside fifth linearLayout.
Here is my parent recyclerview code:
class CardAdapter extends RecyclerView.Adapter<CardAdapter.MyViewHolder>
{
RecyclerView insideCardRecyclerView,recyclerView;
List<String> monthsWeek = new ArrayList<>();
List<String> dealers = new ArrayList<>();
List<String> dealersList = new ArrayList<>();
List<String> date = new ArrayList<>();
HashSet<String> dealersListHash = new HashSet<>();
public CardAdapter(List<String> monthsWeek,List<String> dealers,List<String> date)
{
this.monthsWeek = monthsWeek;
this.dealers = dealers;
this.date = date;
}
public class MyViewHolder extends RecyclerView.ViewHolder
{
ProgressBar progressBar;
RecyclerView recyclerView;
TextView period;
LinearLayout linearLayoutParent,linearLayoutCardDetails;
public MyViewHolder(View view)
{
super(view);
linearLayoutParent = (LinearLayout) view.findViewById(R.id.card_view_linear_parent_layout);
linearLayoutCardDetails = (LinearLayout) view.findViewById(R.id.linear_card_layout_details);
period = (TextView) view.findViewById(R.id.period_summary_graph_card);
insideCardRecyclerView = (RecyclerView) view.findViewById(R.id.summary_graph_card_view_recycler_view);
}
}
#Override
public CardAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
View itemView = LayoutInflater.from(getActivity())
.inflate(R.layout.summary_card_view,parent,false);
recyclerView = (RecyclerView) parent;
return new CardAdapter.MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(final MyViewHolder holder, final int position)
{
holder.period.setText(monthsWeek.get(position));
holder.linearLayoutParent.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view)
{
if(searchClick)
{
for (String date1 : date)
{
if(Objects.equals(date1,monthsWeek.get(position)))
{
Log.e("Summary123 date..///", date1);
dealersList.add(dealers.get(date.indexOf(date1)));
}
}
searchClick = false;
holder.linearLayoutCardDetails.setVisibility(View.VISIBLE);
dealersListHash.addAll(dealersList);
dealersList.clear();
dealersList.addAll(dealersListHash);
//if the condition is true i am attaching another recyclerview inside this.
cardAdapterList = new CardAdapterList(dealersList);
LinearLayoutManager mLayoutManager1 = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL,true);
mLayoutManager1.setReverseLayout(false);
insideCardRecyclerView.setLayoutManager(mLayoutManager1);
insideCardRecyclerView.setItemAnimator(new DefaultItemAnimator());
insideCardRecyclerView.setAdapter(cardAdapterList);
}
else
{
searchClick = true;
holder.linearLayoutCardDetails.setVisibility(View.GONE);
}
}
});
}
#Override
public int getItemCount() {
return monthsWeek.size();
}
}
I've been in trouble sometimes with RecyclerView when multiple lists are needed to be shown in a single page of the application. Its not a very good idea actually to have multiple lists in a single layout but however, the idea of having a ScrollView and the lists inside that ScrollView is even worse.
I had to implement a ListView inside a ScrollView once and yes it was not a very good experience. Firstly, my list was not scrolling at all. Then I had to add some code to disable the scrolling when the touch is detected inside the list. It was not a very good idea of solving the actual problem. I had another problem of having a fixed height of the ListView. In case of list items with dynamic heights, the solution failed.
Having two lists in the layout, one after one is not a good idea either. As the first list need to have a fixed height.
So, after searching for suggestions about how can I implement two lists in a single layout file, I found most of the developers suggests of having a single list with a header and footer if necessary. Later, I could manage to show two lists in a single RecyclerView using my custom Adapter. I thought I should save some of my code for future use and hence, you see this note.
You can refer this sample code.
In my application, I want to scroll to a specific TextView in a RecyclerView if an intent specifies to scroll there. The original implementation involved looking at a listView, and looking at each item in it until I found a string matching the expected TextView string. I'm not sure how to replicate this for a RecyclerView. The closest I got to it was to look at the PreferenceGroupAdapter, but it seems to be a restricted class.
Create a method that returns the position of that TextView within your adapter. For this example, I created a very simple RecyclerView.Adapter that just holds a List<String> items and is looking for the string "target".
private int getTargetPosition(RecyclerView recycler) {
MyAdapter adapter = (MyAdapter) recycler.getAdapter();
for (int i = 0; i < adapter.items.size(); i++) {
if (adapter.items.get(i).equals("target")) {
return i;
}
}
throw new AssertionError("target is guaranteed to be in the list");
}
After that, it's as easy as calling scrollToPosition():
int position = getTargetPosition(recycler);
recycler.scrollToPosition(position);
I am fetching the JSON data via URL and displaying it in text view inside the horizontal scroll view.
JSONArray ja = response.getJSONArray("results");
ArrayList<Details> myModelList = new ArrayList<Details>();
for (int i = 0; i < ja.length(); i++) {
JSONObject jsonObject = ja.getJSONObject(i);
mymodel = new Details();
mymodel.id = Integer.parseInt(jsonObject.optString("id").toString());
mymodel.url = jsonObject.getString("resLink");
mymodel.resType = jsonObject.getString("resType");
mymodel.name = jsonObject.getString("resName");
myModelList.add(mymodel);
setData(myModelList);
I am showing my data in text view but it shows the first data only
private void setData(List<Details> mList) {
for (int i =0; i <=mymodel.getResType().length();i++)
{
TextView textView = (TextView) findViewById(R.id.textView);
textView.setText(mymodel.getResType());
}
You are initializing the mymodel in the for loop again and again so I think it contains only one value that too the last one(not the first one).
If that is the problem, try declaring the following outside the for loop.
mymodel = new Details();
So there's quite a few problems in your code:
1) You are always replacing the text of the same TextView. Normally with scrolling views you back them up with an adapter, place your data into the list that is then added to the adapter, then rely on the scrolling list to dynamically create the TextView which you can populate. If you have a known number of views in your scroll view and you want to avoid adapters, make sure they all have unique IDs so that you could find them.
2) Second problem is you're calling your setData inside the loop. Finish the loop first, then call you method (although you won't really have to do this if you do the adapter thing)
3) Your setData method is all sorts of wrong. If you want to pass a list to a method then iterate through it, you do it like this:
for (Details d : list) {
TextView textView = (TextView) findViewById(R.id.textView);
textView.setText(d.getResType());
}
But like I said, that probably won't help you on its own. Look into documentation for the scroll lists or recycler view and adapters. There are many examples available around.
I have created a dynamic ListView where objects are added from top.
When the user press a button the listView is updated from the contents of an array, then notifyDataSetChanged() is called on the custom arrayAdapter.
Now I want to mantain the list position when adding, so I added this code:
// pausedCounter trace the number of objects(lines) to add to the listView
int idx = listView.getFirstVisiblePosition() + pausedCounter;
View first = listView.getChildAt(0);
int position = 0;
if (first != null)
position = first.getTop();
// cycle to add the new objects to the listView
for (Tweet[] tweets1 : pausedTweets)
super.updateTweets(tweets1);
listView.setSelectionFromTop(idx, position);
// reset of counter and accumulator
pausedTweets = new ArrayList<Tweet[]>();
pausedCounter = 0;
This code behave in this way: if the getFirstVisiblePosition returns 2, and the pausedCounter is 5, after the update the list will be set to the 3th of the new five elements.
What I want is to have the first visible element of the list set to the 8th.
After further tests I found out that the number of childrens of the listView doesn't change during the run of this piece of code, so it updates the size of the listView after I called setSelectionFromTop. Could be this the problem?
The trick was this:
listView.post(new Runnable() {
#Override
public void run() {
listView.setSelectionFromTop(idx, finalPosition);
}
});
Using the post method permits to wait the update of the ListView before change position.
I have added a TextView dynamically in a loop. On a button click, I want to clear the existing text in the text view and set some other text to it. How can I do this?
This is my current code:
ArrayList<String> Cheif_ComplaintNew = new ArrayList<String>();
int cc_Arraylist_length = Cheif_ComplaintNew.size();
android.widget.TextView cc_new = new android.widget.TextView(getApplicationContext());
for(int i=0; i<cc_Arraylist_length; i++)
{
cc_new.setId(i);
cc_new.setText(Cheif_ComplaintNew.get(i));
cc_new.setTextColor(getResources().getColor(R.color.black));
cc_new.setTypeface(null,android.graphics.Typeface.ITALIC);
cc_new.setTextSize(14);
cc_linearNew.addView(cc_new);
System.out.println("id"+i);
}
On a button click, the list is cleared and new data is stored in it. I want to display the new data in the same text view by clearing the old one.
You can either add the text to the textbox when you are creating it or assign it a class variable when you create it and later on you can add text to it.
TextView dynamicTextView;
...
private void CreateNewTextView()
{
dynamicTextView = Your New Text View;
}
...
private void ChangeTheText()
{
dynamicTextView.SetText("new value");
}
if you have more than one TextView you can create a class level generic list of TextViews and add them to the list and call them later.
you can also create a map of all TextView so you can call them with their key as well.
I think you can set a tag to cc_new before add it to cc_linearNew, like this: cc_new.setTag(i). when button got click, you can find those TextView by cc_linearNew.findViewByTag(i) in loop, and set new data to them.
Depends on how many TextViews you need to add to the layout dynamically.
As per the code mentioned, no TextViews are added to the layout as: Cheif_ComplaintNew.size() would return "0" so your loop will not be executed.
If you have to add only one TextView, then I agree with Daniel's answer of having a class level TextView variable.
If its multiple TextViews and you know which ID to use then in your Activity you can always get that TextView by calling findViewById("ID_OF_THE_TEXTVIEW_NEEDED")
You can do this in many ways, some of them :
Store your just created ids in array. Then just get your views calling parentView.findViewById(arreyOfIds(0));
Bad for performance do not do this :) - remove all of just added views from your parentView and create them one more time.
To handle back click in Activity use :
#Override
public void onBackPressed()
{
clearTextView();
}
All of this will simple look like this :
private List<Integer> ids = new ArrayList<Integer>();
#Override
public void onBackPressed()
{
clearTextView();
}
private void clearTextView()
{
for(Integer id : ids)
{
TextView view = (TextView)findViewById(id);
view.setText("")
}
}
private void createTextViews()
{
ArrayList<String>Cheif_ComplaintNew = new ArrayList<String> ();
int cc_Arraylist_length=Cheif_ComplaintNew.size();
android.widget.TextView cc_new = new android.widget.TextView(getApplicationContext() );
for(int i=0; i<cc_Arraylist_length; i++)
{
ids.add(i)
cc_new.setId(i);
cc_new.setText(Cheif_ComplaintNew.get(i));
cc_new.setTextColor(getResources().getColor(R.color.black));
cc_new.setTypeface(null,android.graphics.Typeface.ITALIC);
cc_new.setTextSize(14);
cc_linearNew.addView(cc_new);
System.out.println("id"+i);
}
}