Is there anyway to prevent double tap on ListView in Android? I found this when i accidentally tapped item on ListView and it opened up two new window. is there any way to prevent it from opening a same window twice.
Just add listView.setEnabled(false); on select of listview and after select when response will come or back button press just write---- listView.setEnabled(true);
You should restrict the target activity (one that opens when an item is clicked) to have only one instance at any point of time.
Answer to this SO question should help you in achieving that. That way if you accidentally double click, you will still see just one new screen.
Have a try with introducing and Override of isEnabled method
#Override
public boolean isEnabled(int position) {
return false;
}
for the listview.
introduce a boolean for flag and an int to maintain last clicked position
int recentlyClickedPoisition;
boolean flagRecentClickedPoisition;
override the isEnabled method as follows
#Override
public boolean isEnabled(int position) {
if (flagRecentClickedPoisition && recentlyClickedPoisition == position) {
return false;
} else {
return true;
}
}
than set the last clicked position from your click listener as follows
public void setLastClickedPoisition(int recentlyClickedPoisition) {
flagRecentClickedPoisition = true;
this.recentlyClickedPoisition = recentlyClickedPoisition;
}
Hope this will work for you to prevent from double tap, enhance accordinly.
If you are using just single item like TextView in list then just create a class implements OnItemClickListener in this call and then in to onItemClick() method initialize myListView.setOnItemClickListenet(null);
then use Handler.postDelayed method to again set onItemClickListener.
like
myListView.setOnItemClickListener(new MyClickListenerClass());
This is working for all time in my case.
In your XAML view page place isEnable property as a bindable and two way mode.
<ListView ItemsSource="{Binding items}"
x:Name="listview"
HasUnevenRows="True"
IsEnabled="{Binding IsEnable, Mode=TwoWay}"
RowHeight="10"
SelectionMode="Single"
VerticalScrollBarVisibility="Never">
In viewmodel of your xaml page :
private bool _isEnable = true;
public bool IsEnable
{
get => _isEnable;
set
{
_isEnable = value; OnPropertyChanged(nameof(IsEnable));
}
}
public ICommand TapCommand => new Command<//Model>(async (obj) =>
{
IsEnable = false;
//your stuff
IsEnable = true;
});
I have a two pane layout, a listview that controls a detail view. First I thought a delayed handler is the worst idea, but after testing it is the simplest. Otherwise I would have to communicate between activity and fragment to enable the listview item once another detail was loaded. Error prone and complex.
/*example with Handler():*/
final boolean[] allowClick = {true};
myview.setOnClickListener(v -> {
//exit if not allowed
if(!allowClick[0])
return;
//do stuff
//we clicked, block another click
allowClick[0] =false;
//wait 0.7 seconds and allow another click
new Handler().postDelayed(() -> allowClick[0] =true, 700);
});
This solution is implemented on a ListFragment. If the tap dismissed the ListFragment to show a detail view (which it normally would), the next time the ListFragment appears, the tap counter is reset in OnResume():
public class MyListFragment extends ListFragment {
int mTapCounter;
#Override
public void onResume() {
super.onResume();
//Set-Reset ListView clickListener
mTapCounter = 0;
}
//ListView item tap event handler
#Override
public void onListItemClick(#NonNull ListView l, #NonNull View v, int position, long id) {
//Disable click listener to prevent double-tap
mTapCounter++;
//Only process single-tap
if(mTapCounter == 1) {
/* YOUR TAP HANDLER CODE HERE */
}
super.onListItemClick(l, v, position, id);
}
}
Related
Iam showing the a recyclerview in my app and I want when user click on the recyclerview item a hidden view should be visible to him and on clicking back the item it should gone.
My code :
holder.parentView.setOnClickListener(v -> {
if (viewVisibiltyCheck) {
holder.expandView.setVisibility(View.VISIBLE);
viewVisibiltyCheck = false;
} else {
viewVisibiltyCheck = true;
holder.expandView.setVisibility(View.GONE);
}
});
Iam using Firebase Recycler.I have a boolean check which is when true view become visible of which ever item in list I click and make boolean false.Now if I click on the same item it will work fine and hide the view but if I will click on any other item in list with first view being visible I have to double click the item because at first click it will make boolean true as it become false when I click on the first item list and then on second click it will show me the view .
Is there any logic I can do all with single click? Thanku
You don't need that viewVisibilityCheck at all.
holder.parentView.setOnClickListener(v -> {
if (holder.expandView.getVisibility() == View.GONE) {
holder.expandView.setVisibility(View.VISIBLE);
} else {
holder.expandView.setVisibility(View.GONE);
}
});
If I understand correctly your problem is that the viewVisibiltyCheck value is not connected to the right item you are clicking. If that's the case just set the viewVisibiltyCheck as a property of the holder, so you'll access it the same as the expandView.
So something like this maybe:
holder.parentView.setOnClickListener(v -> {
if (holder.viewVisibiltyCheck) {
holder.expandView.setVisibility(View.VISIBLE);
holder.viewVisibiltyCheck = false;
} else {
holder.viewVisibiltyCheck = true;
holder.expandView.setVisibility(View.GONE);
}
});
EDIT:
You need to put it where you create the holder and its views, like the expandView. In this way you can associated various parameters to the view, but Bruce answer it's easier probably in your case.
public class MyViewHolder extends RecyclerView.ViewHolder {
View expandView;
boolean viewVisibiltyCheck;
public MyViewHolder(View itemView) {
super(itemView);
/* your code */
viewVisibiltyCheck = false;
}
I have a layout with three spinners. They differ in the option presented in the drop-down.
In my onCreateView I have a method to setup the spinners. Inside that method I have something like this:
mySpinner = (Spinner) view.findViewById(R.id.my_spinner);
ArrayAdapter<String> mySpinner =
new ArrayAdapter<String>(getActivity(), R.layout.background,
new ArrayList<String>(Arrays.asList(getResources().getStringArray(R.array.spinner_one_data))));
mySpinner.setDropDownViewResource(R.layout.spinner_text);
mySpinner.setAdapter(mySpinner);
mySpinner.setOnItemSelectedListener(this);
As I said, my other two spinners are almost the same but with different options.
I know that onItemSelected is called once for every spinner in a "first setup" so I have a flag to prevent this problem. With this flag solution, my spinners are working as expected.
The problem is when I select in each spinner an option and then rotate the screen. Now, onItemSelected is called 6 times instead the 3 times that I was expecting (I've set a flag to manage this situation of the 3 times calling).
Why Is it happening and hoe should I handle this?
In general, I've found that there are many different events that can trigger the onItemSelected method, and it is difficult to keep track of all of them. Instead, I found it simpler to use an OnTouchListener to only respond to user-initiated changes.
Create your listener for the spinner:
public class SpinnerInteractionListener implements AdapterView.OnItemSelectedListener, View.OnTouchListener {
boolean userSelect = false;
#Override
public boolean onTouch(View v, MotionEvent event) {
userSelect = true;
return false;
}
#Override
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
if (userSelect) {
// Your selection handling code here
userSelect = false;
}
}
}
Add the listener to the spinner as both an OnItemSelectedListener and an OnTouchListener:
SpinnerInteractionListener listener = new SpinnerInteractionListener();
mSpinnerView.setOnTouchListener(listener);
mSpinnerView.setOnItemSelectedListener(listener);
I've found a solution that is working for me.
I have the 3 spinners so onItemSelected is called 3 times at the initial spinner setup. To avoid onItemSelected from firing a method in the initial setup I've created a counter so onItemSelected only fires the method accordingly the counter value.
I've realized that in my situation, if a rotated the screen, onItemSelected is fired again the 3 times, plus a time for each spinner that is not in the position 0.
An example:
I have the 3 spinners and the user changes 2 of them to one of the available option other then position 0 so he ends up with a situation like this:
First spinner - > Item 2 selected
Second spinner -> Item 0 selected (no changes)
Third spinner -> Item 1 selected
Now, wen I rotate the screen, onItemSelected will be fired 3 times for the initial spinner setup plus 2 times for the spinners that aren't at position 0.
#Override
public void onSaveInstanceState(Bundle outState) {
int changedSpinners = 0;
if (spinner1.getSelectedItemPosition() != 0) {
changedSpinners += 1;
}
if (spinner2.getSelectedItemPosition() != 0) {
changedSpinners += 1;
}
if (spinner3.getSelectedItemPosition() != 0) {
changedSpinners += 1;
}
outState.putInt("changedSpinners", changedSpinners);
}
I've saved the state in onSaveInstanceState and then, in onCreateView I checked if savedInstanceState != null and if so, extracted changedSpinners from the bundle and updated my counter to act accordingly.
To expand on Andres Q.'s answer... If you are using Java 8 you can do this with fewer lines of code by making use of lambda expressions. This method also forgoes the need to create a separate class in order to implement onTouchListener
Boolean spinnerTouched; //declare this as an instance or class variable
spinnerTouched = false;
yourSpinner.setOnTouchListener((v,me) -> {spinnerTouched = true; v.performClick(); return false;});
yourSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if(spinnerTouched){
//do your stuff here
}
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
//nothing selected
}
});
What about just to check if fragment is in resumed state? Somethink like this:
private AdapterView.OnItemSelectedListener mFilterListener = new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (isResumed()) {
//your code
}
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
};
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
//set mFilterListener
}
It eliminates the rotation problem and also the first setup problem. No flags etc. I was having the same problem with TextWatchers and found this answer with comment, which inspired me for this solution.
I have a ListView that contains items with checkboxes that should behave sometimes like a CHOICE_MODE_MULTIPLE and sometimes like a CHOICE_MODE_SINGLE. What I mean is for certain items in the list, when selected certain other items needs to be deselected whilst other can remain selected.
So when item A is checked I can find in my data the item B that needs to be unchecked but how do I get the UI to refresh to show this as I (I believe) cannot find the actual View that represents B but just it's data?
It sounds like you're off to a good start. You're right that you should be manipulating the underlying data source for item B when A is clicked.
Two tips that may help you:
Your getView() method in the Adapter should be looking at your data source and changing convertView based on what it finds. You cannot find the actual View that represents B because in a ListView, the Views are recycled and get reused as different data needs to be displayed. Basically, when an item is scrolled off the list, the View that was used gets passed to the getView() function as convertView, ready to handle the next element's data. For this reason, you should probably never directly change a View in a ListView based on user input, but rather the underlying data.
You can call notifyDataSetChanged() from within your adapter to signal that somewhere the underlying data has been changed and getView() should be called again for the elements currently displayed in your list.
If you're still having trouble, feel free to post some code that illustrates the specific problem that you're having. It's much easier to provide concrete advice when the problem is better defined. Hope this helps!
you can use singleChoice alartDialog, i have used like:
private int i = 0; // this is global
private final CharSequence[] items = {"Breakfast", "Lunch", "Dinner"}; // this is global
Button settings = (Button)view.findViewById(R.id.settings);
settings.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View v) {
AlertDialog.Builder builder = new AlertDialog.Builder(v.getContext());
//Title of Popup
builder.setTitle("Settings");
builder.setSingleChoiceItems(items, i,
new DialogInterface.OnClickListener() {
// When you click the radio button
public void onClick(DialogInterface dialog, int item){
i=item;
}
});
builder.setPositiveButton("Confirm",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int item) {
if (i == 0) {
//it means 1st item is checked, so do your code
}
if (i == 1) {
//it means 2nd item is checked, so do your code
} /// for more item do if statement
}
});
//When you click Cancel, Leaves PopUp.
builder.setNegativeButton("Cancel", null);
builder.create().show();
}
});
i have initialized i=0, so that for the very first time when user click on settings button, the first item is selected. and after then when user select other item, i have saved the i value so that next time when user click settings button, i can show user his/her previously selected item is selected.
I come across and solve this question today.
public class ItemChooceActivity extends Activity implements OnItemClickListener {
private int chosenOne = -1;
class Madapter extends BaseAdapter {
.....
.....
#Override
public View getView(final int position, View convertView,
ViewGroup parent) {
// TODO Auto-generated method stub
if (chosenOne != position) {
set the view in A style
} else {
set the view in B style
}
return convertView;
}
}
#Override
public void onItemClick(AdapterView<?> arg0, View view, int position,
long arg3) {
,,,,
chosenOne = position;
adapter.notifyDataSetChanged();
,,,
}
}
Depending on the clicked button out of 3 button, different data gets populated in listView.
I've used this
onListItemClick snippet
//ltable refers to list
String item = ltable.getItemAtPosition(position).toString();
Intent i = new Intent(getApplicationContext(),NextClass.class);
i.putExtra("name", item);
startActivity(i);
Now on any button click, corresponding data gets populated in listView. Then on listItelClick, it navigates to NextClass.class and hence new activity gets launched.
What if I want app to navigate to next view if and only if listView is populated when Gainers or Losers button is pressed????
If listView is populated on Index button click, it should not navigate.
i.e. Clicked button should be captured.
I tried to use flag, but only final variables are permitted within buttonClickListener, so it doesn't work.
How can I implement this??
ANY HELP WILL BE LIFE-SAVER !!!
Take a class level variable
boolean shouldNavigate = false;
and in onClick() of Index Button. set shouldNavigate to false:
public void onClick(View v)
{
// Update adapter for Index..
shouldNavigate = false;
}
But in onClick() of other than Index Button. set shouldNavigate to true:
public void onClick(View v)
{
// Update adapter for Gainer or Losers..
shouldNavigate = true;
}
and inside your onItemClick() check for the flag and navigate accordingly
public void onItemClick(AdapterView parent, View view, int position, long id) {
if(shouldNavigate)
{
// you can navigagte...
}
else
{
// do other task
}
}
When you are in the 'Index' mode, remove the onItemClickListener. Add it back for the other two buttons.
I'm creating a spinner and I've added an OnItemSelectedListener to it.
However I've noticed that it fires on create.
Now I was wondering if there was a way to ignore/discard it.
I know I could use a boolean value, but that's a bit "dirty".
Here is my solution.
I need to ignore the first item selection event because there is a dependency between the Route Grade Spinner and the Route Checkbox.
And all my controls are setup based on a previous visit to the activity.
// Used to count the number of times the onItemSelected gets fired
private int mGradeSelectionCount = 0;
private void attachHandlers() {
OnItemSelectedListener gradeRangeSelectionMadeListener;
gradeRangeSelectionMadeListener = new OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> adapter, View view, int position, long id) {
// If the counter is 0 then we can assume that it is android firing the event
if (mGradeSelectionCount++ < 1) {
return;
}
if (mCmbGradeFrom.getSelectedItemPosition() == 0) {
// Uncheck the Route checkbox
mChkTypeRoute.setChecked(false);
} else {
// Check the Route checkbox
mChkTypeRoute.setChecked(true);
}
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
// Dont care, keep the same values as before
}
};
mCmbGradeFrom.setOnItemSelectedListener(gradeRangeSelectionMadeListener);
mChkTypeRoute.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (!isChecked) {
mCmbGradeFrom.setSelection(0);
mCmbGradeTo.setSelection(0);
}
}
});
}
This may help you.
#Override
public void onItemSelected( AdapterView<?> parent, View view, int position, long id)
{
if(view!=null && view.getId()!=0){
//do your code here to avoid callback twice
}
}
You should not attempt to prevent the call to the OnItemSelectedListener.
By default, Android Spinners select the first item returned by the Adapter, and therefore the OnItemSelectedListener is called to trigger some action on that item.
I would advise that the first item in your Spinner Adapter be a blank item, and your OnItemSelectedListener can ignore that blank item based on its id.
If anyone else comes across this question, it may be worth having a look at a related question I asked a while ago, which has several answers with good ideas on how to work around this issue.
Well I think I found nice solution for me, I had it in mind from start but...
I have custom wrapper class based on android Handler , that is called DoLater, and also there is custom Adapter based on Listener so you cant copy paste this but you will get idea. Dangerous thing is just that somehow delay 500 can be to long and View can be already destroyed (when user do some wired stuff quickly or phone gets slow...) so DoLater cares of that so it is not called when activity is not resumed. But this way OnItemSelectedListener is not fired on create.
public void onResume() {
super.onResume();
new DoLater(this, 500) {
public void run() {
new OnSpinnerSelectedAdapter(getBowSpinner()) {
protected void onItemSelected(int position) {
onBowSelected(position);
}
};
}
};
}