In Android Spinner, I can set selection to a particular Item in the code (using setSelection(int)). This will end up calling OnItemSelectedListener, which is fine.
But when the user selects an item from the screen, by clicking the spinner and the item, I want to handle this as a different event, because the logic in my application should do different things.
How to achieve this?
To summarize, My Spinner should do this
If Value set from the code {
//do this..
}
else if user select a value {
//do that..
}
Extend Spinner and override setSelection(int). Insert functionality you want to happen in this case and then call super.setSelection(int) to keep the Spinner working normally.
I ended up using a global variable to indicate me who is calling the onItemSelected method. Looks like solved my purpose. But any better solutions are welcome.
Related
I have created a chat app by using RecyclerView.
If one of the users in the chat clicks on some button, the following message is sent in the chat:
This message contains a string and 2 buttons that were created in my RecyclerView.
Now, I had like to do some action based on if the second users click confirm or decline.
How can I set a click listener to these buttons?
The buttons were created inside the RecycelerView however I had like that once a user clicked Confirm it will perform an action in the class that is outside the adapter where all my parameters are.
How can I like to return a value from the adapter? Something like if a user clicked Confirm, it will return 1 to the outer class and then I will run some code.
Thank you
You can simply save these values in the sharePreference then retrieve and check them in the outer class then perform needed actions.
create interface like
interface onConfirmClicked{
fun onConfirmed(value:Boolean)
}
implement this into your class and send it to your adapter
class A : onConfirmClicked{
ovveride fun onConfirmed(value: Boolean){
//do what you want here
}
adapter.setOnConfirmClicked(this)
}
into your adapter in the confirm button clickLisnter call this
onConfirmClickListner.onConfirmed(true)
I know this is somewhat of a design question but I do have specific questions for it. I'm trying to understand how to handle a situation like this one:
Let's say I have a RecyclerViewFragment which loads a RecyclerView containing a bunch of Toy objects.
In one situation: Maybe this RecyclerViewFragment is part of a ViewPager on main display. There is a FloatingActionButton add-button present over this RecyclerView. You click the + button and you can add a new Toy to the list. Or you can click a Toy from the list directly and a floating menu pops up with Edit/Delete buttons, and pressing Edit lets you edit the Toy's details in a DialogFragment, or clicking Delete removes it from the RecyclerView.
In another situation: Now I am in a separate part of the app where I want to choose toys to use. So I press a button and a DialogFragment appears with a RecyclerView of Toys. I can click a Toy and it'll be added to my cart.
It seems like I should be re-using the same RecyclerView code in both situations, since they both involve a list of the same Toys. The only difference is that in one situation, I can add Toys and edit Toy details, and in the other situation, there is no Add button and clicking on a toy does something different (adding to a cart as opposed to bringing up an Edit/Delete dialog).
Is this the correct way to handle this:
Communication from Fragment to Activity: Interfaces? Have the RecyclerViewFragment, in the onAttach method, assign a listener of my design to the context. Then when a row of the RecyclerView is pressed, the callback is triggered. Now the underlying Activity can decide what to do with that press -- show the Edit/Delete dialog in one situation, add the Toy to a Cart in the other situation. Either way, the click item sends the Toy to the calling Activity so it can decide what to do with it.
Communication from Activity to Fragment: Now what about the situation with the Add button? This Add button would not be intrinsically part of the RecyclerViewFragment, so when I click Add, it would bring up the details dialog box where I can give the Toy details, and then press OK to add it. So somehow I have to transfer this new Toy to the Fragment to have it added to the RecyclerView. Would I simply do something like this:
RecyclerViewFragment recyclerViewFragment = (RecyclerViewFragment ) getSupportFragmentManager().findFragmentByTag("TOY_RECYCLERVIEW");
recyclerViewFragment.getNewToyAndRefreshList(newToy);
and then in the RecyclerViewFragment:
public void getNewToyAndRefreshList(Toy newToy) {
toyList.add(newToy);
Collections.sort(toyList); //Toy has Comparable implemented, sort by name
recyclerViewAdapter.notifyDataSetChanged();
}
Am I on the right track? Is there a different way to fix this situation?
That's certainly a design question, but IMHO there's a very specific issue on it and I believe it's a good question (reason I'm answering), but that also means other developers might have other approaches to solve the issue.
1. that is a totally fair and acceptable approach to it. You let the fragment be simple UI element and let someone else (the activity) implement the click behavior.
For this approach remember to code it only against the interface. That means, don't cast it to your activity. For example:
// do this
toyClickListener.onToyClicked(toy);
// don't do this
((MyActivity)getActivity()).onToyClicked(toy);
That way you keep the "simple UI element" be completely unaware of who is implementing the behavior.
2. IMO for this kind of scenario (specially on RecyclerView.Adapter) the best thing to do is to forget the UI and only focus on the data. And how speciafically you implement this, will vary on what is your data source.
But the base idea is that you have somewhere a data repo (DB?) and anyone using data from there, should subscribe to changes to it.
So you override RecyclerView.Adapter.registerAdapterDataObserver and unregisterAdapterDataObserver add the subscription/listener code, something like that:
#Override registerAdapterDataObserver(RecyclerView.AdapterDataObserver observer) {
super.registerAdapterDataObserver(observer);
db.subscribe(this, toyList);
}
#Override unregisterAdapterDataObserver(RecyclerView.AdapterDataObserver observer) {
db.unsubscribe(this);
super.unregisterAdapterDataObserver(observer);
}
#Override public void onDbDataUpdate(new Data comes here){
update the data, and call .notifyDataSetChanged();
}
that way once the FAB + and then dialog is clicked the new Toy gets added to the DB and the adapter gets "automatically" notified.
So if this data comes from a SQLite you can call on the cursor registerContentObserver if it's a RealmDB you'll use addChangeListener, even Android databinding libraries have a ObservableList
In Android Studio I have selected a new project based on master / detail flow. The project works as it should be. Now I want to extend it. As of now the content of the items in the detail fragment are only shown when I click an item on the list. I want that the top item is selected automaticaly when the app starts. I thought I put in ItemListFragment just a method call
#Override
public void onStart()
{
mCallbacks.onItemSelected(DummyContent.ITEMS.get(0).id);
}
that a click is simulated in the lifecycle once all objects are initialized. That fails. What is the best way of doing this?
You can select the first element by the following code
yourListView.setSelection(0);
yourListView.getSelectedView().setSelected(true);
Hope this helps. Cheers mate! :)
You can use SharedPreferences. You can save first item of listview as preference when create listview, then you can use it later.
Have you try it in onResume()? I always put it in onResume()
UPDATE #1
You can try my way to implement the selection. Normally i don't use the select of list view.
1.In your data model, create a boolean field called "selection".
2.When you apply data to your adapter, set the first data "selection" to true.
3.In your adapter getView callback, try to handles your data "selection" such as:
if (!dummyData.selection){
do something when not select....
}else{
do something when selected...
}
UPDATE #2
put this code in ItemListFragment
#Override
public void onResume() {
super.onResume();
mCallbacks.onItemSelected(DummyContent.ITEMS.get(0).id);
}
I am using two spinners. The items in second spinner gets populated dynamically based on the selection of the item of first spinner. I have implemented OnItemSelectedListener and overridden onItemSelected to achieve this. I am also using SharedPreferences to persist certain data to take care of screen rotation. The trouble I am facing is that, everything works perfectly fine and as expected with android version 4.0 but the same code fails to work with above versions of android(4.1, 4.2, 4.3) and selected item of second spinner resets on screen rotation. What is driving me nuts is, with android version 4.0 things work perfectly fine. Any suggestions?
I have no idea what it could possibly have to do with versions > 4.0, however it might be a better idea to handle a configuration change by writing the data you want to keep into the bundle in onSaveInstanceState(Bundle out) and read it in onCreate(Bundle savedInstance).
Even though it won't "fix" the strange behavior you are seeing, but it should work...
In my opinion is not a good idea to use SharedPreferences to persist that data. at the same time is not good idea to put a Spinner in the onSaveInstanceState() Bundle. Besides the fact that it is impossible, doing so would cause your new activity to hold onto a reference to that Spinner, which holds onto a reference to your old activity, which will cause a substantial memory leak.
Your Spinner's contents are set via some sort of Adapter. You should be making sure your new Activity can re-create that Adapter. Then, put either getItemSelectedId() or getItemSelectedPosition() in the Bundle, so you can restore the selection in the new Activity.
I found a solution, although is not perfect, more of a hook, if the screen is rotated , I am assuming the item selected item of first spinner and its index will be same(as i am dealing with natural numbers) so i am setting the data in the second spinner accordingly, otherwise creating a new spinner and setting the required data in that, in the onItemSelected listener of the first spinner. Not very clean, but works for me (for 4.0 and above versions). if(firstSpinnerItemSelected != position || firstSpinnerItemSelected == 0){
firstSpinner.setSelection(secondSpinnerItemSelected, true);
ArrayAdapter secondAdapter = new ArrayAdapter(
context, R.layout.spinner_item, itemList);
secondSpinner.setAdapter(secondAdapter);
}
else{
secondSpinner.setSelection(secondSpinnerItemSelected, false);
}
Try to implement methods
onSaveInstaceState() // to save current selected items;
and
onRestoreInstanceState() // to select saved items.
Or you can add to your manifests activity tag
android:configChanges="orientation"
then your activity wont be recreated, and everything should be the same
How can we handle the check button in the CAB menu?
Is the item associated to some internal id like android.R.id.checkbox?
I've read that it could be handled in SherlockActionBar CAB, but could it be the same with the native ActionBar CAB?
Is there any way to detect the interaction of this item? onActionModeFinished() is not sufficient since I'm calling it multiple times since the CAB needs to be present due to previous changes that happened.
Thanks.
Ok, finally found a solution after trying some things.
Place the code you want for the checkbox or onbackpressed in the method below
public void onDestroyActionMode(ActionMode mode)
{
//place the code you want for the checkbox or back icon here. If you don't want
// this code run if other selections are used, then just create a boolean value that
//you earlier on and check the value in this section before implementing the code
}
};