To use ActivityOptionsCompat.MakeScaleUpAnimation(), I need access to the View from where the animation originates. I use MvvmCross, so I need to pass via a MvxFragmentsPresenter (shouldn't be relevant to the problem). A ViewModel request can contain key/value parameters. So I attach a Tag to each RecyclerView item and then pass on that Tag as a parameter in the ViewModel request, as done here. I can access this tag in the presenter.
Now inside the presenter I need to find the RecyclerView item that was clicked. I want to do this as follows:
View contentFrame = Activity.FindViewById(Resource.Id.content_frame);
View recyclerView = contentFrame.FindViewById(Resource.Id.recycler_view);
View item = recyclerView.FindViewWithTag("mytag");
Unfortunately this results in null. I can access the contentFrame and the recyclerView, but not an item by Tag. However I can even get the first item using:
recvddfg.GetChildAt(0);
... and access the Tag! So it's strange that FindViewWithTag isn't working. Does anyone have an idea?
After searching for hours, I decided to post this question. Then looked back at it and found the cause: I was searching for an item with a tag of type string, while I should have been searching for a number... You can use any type you want with a Tag, so in your case it might be different if you have the same problem. You just need to be consistent.
Related
I'm new to all of this and was making good progress but I have hit a brick wall with working out how to do the next thing. I am using Kotlin and have a Fragment with an associated Recyclerview Adapter. I would like to set OnClick (On or Off) against items in a row depending upon a value in the Fragment which could change at any time.
My adapter works fine to show and update the array of data and also to implement OnClick.
I have tried sending a data element via a constructor which changed in the fragment but always showed as the initial setting in the adapter. The same with trying to call a method.
Many other questions touch on the issue but only show snippets of code, and it seems that I'm not advanced enough to get them working successfully in my code.
Could anyone please provide a pointer to a working set of Kotlin code that includes parsing a variable from fragment to adapter - perhaps in Git or a tutorial. I'm sure that if I can study a working program I can move forward. Thank you.
It would have been better if you had included your Adapter and Fragment code in the question, that would have helped us in understanding how you have setup everything and what data model are you passing to adapter.
But looking at your question, one solution that comes to my mind is to add an enabled boolean in your data model that is displayed in the ViewHolder. Using this you can set view.clickable = model.enabled. Now whenever your "value in the Fragment" changes you can update this list and let the adapter rebind items.
Note that the above solution is when you want to selectively enable/disable clicks on individual items. If you want to do this for all items at once, it's better to create a variable in adapter that you can change from the Fragment, and inside the clickListener you can check the value of that adapter variable. If it's false, just return out of the click listener. Something like,
view.setOnClickListener {
if(adapterValue) {
// handle Click
}
}
If this approach doesn't help, I would ask you to add more context in your question and show what you have done so far.
I use shared RecycledViewPool between some Fragments. I decided to try out MergeAdapter in one fragment. For that screen, I created a separate adapter for each viewType and overrode getItemViewType method to return layout ID as view type.
When I go to any other screen that has shared RecycledViewPool but is not using MergeAdapter I see some of the viewHolders from previous screen showing up. When I return back app crashes and in logs I see ClassCastException saying that ViewHolder1 cannot be casted to ViewHolder2.
My code looks like this:
recyclerView.setRecycledViewPool(sharedViewPool)
val adapter = MergeAdapter(adapter1, adapter2, adapter3, adapter4)
recyclerView.adapter = adapter
How to keep shared RecycledViewPool, but eliminate ClassCastException and stop showing ViewHolders in other screens where they should not be shown?
After digging more into the documentation I found that the problem was MergeAdapter with default configuration.
from documentation:
By default, MergeAdapter isolates view types of nested adapters from each other such that it will change the view type before reporting it back to the RecyclerView to avoid any conflicts between the view types of added adapters. This also means each added adapter will have its own isolated pool of RecyclerView.ViewHolders, with no re-use in between added adapters.
If your RecyclerView.Adapters share the same view types, and can support sharing RecyclerView.ViewHolder s between added adapters, provide an instance of MergeAdapter.Config where you set MergeAdapter.Config.isolateViewTypes to false. A common usage pattern for this is to return the R.layout. from the RecyclerView.Adapter.getItemViewType(int) method.
I also read this in article written by Florina Muntenescu and for some reason I thought that isolateViewTypes is only affecting adapters added to one MergeAdapter. But since in default config it will modify returned view types for each ViewHolder it might (most likely will) cause inconsistency in shared RecycledViewPool. Not sure if it is a bug or expected behaviour. Would be great to hear something from team working on RecyclerView.
Solution was setting isolateViewTypes to false.
val adapter = MergeAdapter(
MergeAdapter.Config.Builder().setIsolateViewTypes(false).build(),
adapter1,
adapter2,
adapter3,
adapter4
)
I think it is pretty easy mistake to make and I hope this solution will save some time for others.
I have implemented a firebase list adapter to load a list of items (List A). My data structure is setup such that within List A, each item also contains a reference id to some information located somewhere else (isNice) in the database. Likewise:
ListA
- ObjA
- title : "hi"
- id : "ObjAid"
isNice
- ObjAid : "true"
I'm currently using another database operation to look up the id in the "isNice" child, passing the "ObjAid", the list position, and then a resultReceiver to get the result back. My problem is, when the resultReceiver get a resultData (the value "true"), I have no idea how modify the data within firebase list at the specific position.
My past experience is to use load my data into my own ArrayList and create a custom adapter for the listView, in that case, I could easily update the populated view as extra information is loaded. I would like to avoid setting up my own ArrayList to store the data for the time being, favoring the simplicity of the FirebaseListAdapter. All tips are appreciated, thx :)
After some trial and error, I've instead gone with the RecyclerView + FirebaseRecyclerViewAdapter approach. Using recycler is better for the long run too, in my use case the list could get to 3K+. Using RecyclerView.findViewHolderForAdapterPosition() I can reference the specific itemView after I get the data from the result receiver likewise:
// Reference the Item's view at the specific position
myViewHolder itemViewHolder = recyclerView.findViewHolderForAdapterPosition(position);
// Reference and set the views and here......
I'm trying to click on a item at a specific position in a grid view.
onData(instanceOf(MyClass.class))
.inAdapterView(withId(R.id.my_view))
.atPosition(R.integer.my_id)
.perform(click());
but I'm getting this java.lang.IndexOutOfBoundsException: Invalid index 0, size is 0
I'm queuing the responses using MockWebServer, even after the UI is on screen with all the list item, I'm getting this error, I'm not sure why.
Also, I want to get the content of the specific item.
Well, I think that's because you're matching class which is only one, not a specific adapter with values.
Please consider this post:
The matcher passed as argument to onData() must match the value as
returned by Adapter.getItem(). So the first version doesn't match,
because of the wrong type being used. It should be:
onData(is(instanceOf(IconRowAdapter.IconRow.class)))
What also can be a pitfall is using equalTo on different kinds of
CharSequences. String is a CharSequence, but if IconRow.getText()
returns CharSequence instead of String, then this can also be
Spannable, Editable, etc in which case equalTo wouldn't match. So if
IconRow.getText() return anything but String, make sure to convert it
into a String before comparison.
This post was taken from How to use Espresso to test item in adapter at a specific position
Your question lacks of code of tested class, so I cannot give you direct answer. I can only recommend to read StackOverflow link above.
Hope it help
You may need to "drill down" a little deeper into the view hierarchy to get to the item in the cell. Put an additional method call before the ".perform" using the id of the item in the grid cell
onChildView(withId(R.id.???)).perform(click());
Use the id of the view that the user would click on.
I have a set of View instances that each represent some different data object (derived from Java.Lang.Object). I associate each view with its data object by setting the view's tag reference. The views can generate context menus, and in the onCreateContextMenu function I can get the source view and then get the data object from its tag.
My problem is that I can't find a way to associate the data object with the created menu or menu item such that I can get the data item in onContextItemSelected().
How do I propagate the data item to onContextItemSelected()?
UPDATE
From the link posted by #asktomsk it looks like what I want to do is only possible (without a lot of subclassing) if the originating view is a ListView. Having also read this on the android developer site I suspect that long-tough context menus are probably not advisable anyway, and that I should find a different mechanism.
Check the MenuItem.getMenuInfo() data. It contains information about context menu caller.
Some explanation you may found here:
Identifying the view selected in a ContextMenu (Android)