Is there a way to execute when the same Position is selected?
For example, if 0 is currently selected, selecting 0 again will cause the same event to occur again.
Create a Custom Class that extends Spinner and replace it with your Spinner
public class NDSpinner extends Spinner {
public NDSpinner(Context context) {
super(context);
}
public NDSpinner(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NDSpinner(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public void
setSelection(int position, boolean animate) {
boolean sameSelected = position == getSelectedItemPosition();
super.setSelection(position, animate);
if (sameSelected) {
// Spinner does not call the OnItemSelectedListener if the same item is selected, so do it manually now
getOnItemSelectedListener().onItemSelected(this, getSelectedView(), position, getSelectedItemId());
}
}
#Override
public void
setSelection(int position) {
boolean sameSelected = position == getSelectedItemPosition();
super.setSelection(position);
if (sameSelected) {
// Spinner does not call the OnItemSelectedListener if the same item is selected, so do it manually now
getOnItemSelectedListener().onItemSelected(this, getSelectedView(), position, getSelectedItemId());
}
}
}
Related
I want to disable recyclerview scrolling in landscape mode and enable it in the portrait mode.
recyclerView.addOnItemTouchListener(new RecyclerView.SimpleOnItemTouchListener() {
#Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
// Stop only scrolling.
return rv.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING;
}
});
I am using this method to disable scrolling but can't find a way to enable it again.
Thanks for any help!
You have to get it done using a custom RecyclerView. Initialize it programmatically when the user is in landscape mode and add this view to your layout:
public class MyRecycler extends RecyclerView {
private boolean verticleScrollingEnabled = true;
public void enableVersticleScroll (boolean enabled) {
verticleScrollingEnabled = enabled;
}
public boolean isVerticleScrollingEnabled() {
return verticleScrollingEnabled;
}
#Override
public int computeVerticalScrollRange() {
if (isVerticleScrollingEnabled())
return super.computeVerticalScrollRange();
return 0;
}
#Override
public boolean onInterceptTouchEvent(MotionEvent e) {
if(isVerticleScrollingEnabled())
return super.onInterceptTouchEvent(e);
return false;
}
public MyRecycler(Context context) {
super(context);
}
public MyRecycler(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
}
public MyRecycler(Context context, #Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
}
For portrait mode keep using your normal RecyclerView.
For this issue, I use this one line solution! :)
myRecyclerView.isNestedScrollingEnabled = false
I am using PreferenceActivity for the setting of my app.
I want to add a new preference that allow the user to select an icon.
For this task I want to use a ListPreference, but I want also to show the icon in the list.
I tried to customize the ListPreference to use a custom layout, but the problem is that once I do that the list items are not clickable (it does show my custom layout and use the default value for the current selection).
I tested it on different emulator version and on Galaxy S2. When pressing the item I could see some effect of the pressed/unpressed, but the onClick method is not called.
I followed the instruction on Android: Checkable Linear Layout for adding custom layout (I also tried the option describe in How to customize list preference radio button, but the same result).
IconTypePreference.java (copied from ListPreference and modified):
public class IconTypePreference extends DialogPreference {
private IconType value;
private int clickedDialogIndex;
private boolean valueSet;
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public IconTypePreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public IconTypePreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public IconTypePreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public IconTypePreference(Context context) {
super(context);
}
public void setValue(String value) {
// Always persist/notify the first time.
final boolean changed = !TextUtils.equals(getValueText(), value);
if (changed || !valueSet) {
if (value == null) {
this.value = null;
} else {
this.value = IconType.valueOf(value);
}
valueSet = true;
persistString(value);
if (changed) {
notifyChanged();
}
}
}
public void setValueIndex(int index) {
setValue(IconType.values()[index].toString());
}
public IconType getValue() {
return value;
}
public String getValueText() {
return (value == null ? null : value.toString());
}
public int findIndexOfValue(String value) {
IconType[] values = IconType.values();
for (int i = values.length - 1; i >= 0; i--) {
if (values[i].toString().equals(value)) {
return i;
}
}
return -1;
}
private int getValueIndex() {
return findIndexOfValue(getValueText());
}
#Override
protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
super.onPrepareDialogBuilder(builder);
clickedDialogIndex = getValueIndex();
builder.setSingleChoiceItems(new IconTypeAdapter(getContext()), clickedDialogIndex,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
clickedDialogIndex = which;
IconTypePreference.this.onClick(dialog, DialogInterface.BUTTON_POSITIVE);
dialog.dismiss();
}
});
/*
* The typical interaction for list-based dialogs is to have
* click-on-an-item dismiss the dialog instead of the user having to
* press 'Ok'.
*/
builder.setPositiveButton(null, null);
}
#Override
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
if (positiveResult && clickedDialogIndex >= 0) {
String value = IconType.values()[clickedDialogIndex].toString();
if (callChangeListener(value)) {
setValue(value);
}
}
}
#Override
protected Object onGetDefaultValue(TypedArray a, int index) {
return a.getString(index);
}
#Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
setValue(restoreValue ? getPersistedString(getValueText()) : (String)defaultValue);
}
#Override
protected Parcelable onSaveInstanceState() {
final Parcelable superState = super.onSaveInstanceState();
if (isPersistent()) {
// No need to save instance state since it's persistent
return superState;
}
final SavedState myState = new SavedState(superState);
myState.value = getValueText();
return myState;
}
#Override
protected void onRestoreInstanceState(Parcelable state) {
if (state == null || !state.getClass().equals(SavedState.class)) {
// Didn't save state for us in onSaveInstanceState
super.onRestoreInstanceState(state);
return;
}
SavedState myState = (SavedState)state;
super.onRestoreInstanceState(myState.getSuperState());
setValue(myState.value);
}
private static class SavedState extends BaseSavedState {
String value;
public SavedState(Parcel source) {
super(source);
value = source.readString();
}
#Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeString(value);
}
public SavedState(Parcelable superState) {
super(superState);
}
public static final Parcelable.Creator<SavedState> CREATOR =
new Parcelable.Creator<SavedState>() {
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
private static class IconTypeAdapter extends ArrayAdapter<IconType> {
private final String[] iconTypeText;
private LayoutInflater inflater;
public IconTypeAdapter(Context context) {
super(context, R.layout.icon_type_item, IconType.values());
this.inflater = LayoutInflater.from(context);
iconTypeText = context.getResources().getStringArray(R.array.icon_type);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = inflater.inflate(R.layout.icon_type_item, parent, false);
}
((TextView)convertView.findViewById(R.id.text)).setText(iconTypeText[position]);
convertView.setClickable(true);
// todo: set view text
return convertView;
}
#Override
public boolean hasStableIds() {
return true;
}
#Override
public long getItemId(int position) {
return position;
}
}
}
CheckableLinearLayout.java
public class CheckableLinearLayout extends LinearLayout implements Checkable {
private Checkable checkable;
public CheckableLinearLayout(Context context) {
super(context);
}
public CheckableLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public CheckableLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public CheckableLinearLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
// setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
checkable = getCheckable(this);
if (checkable == null) {
throw new RuntimeException("Missing Checkable component");
}
}
private Checkable getCheckable(ViewGroup viewGroup) {
View v;
int childCount = viewGroup.getChildCount();
for (int i = 0; i < childCount; ++i) {
v = getChildAt(i);
if (v instanceof Checkable) {
return (Checkable)v;
} else if (v instanceof ViewGroup) {
Checkable result = getCheckable((ViewGroup)v);
if (result != null) {
return result;
}
}
}
return null;
}
#Override
public void setChecked(boolean checked) {
checkable.setChecked(checked);
}
#Override
public boolean isChecked() {
return checkable.isChecked();
}
#Override
public void toggle() {
checkable.toggle();
}
}
icon_type_item.xml
<?xml version="1.0" encoding="utf-8"?>
<com.utils.ui.widget.CheckableLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView android:id="#+id/text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:focusable="false"
android:focusableInTouchMode="false"/>
<RadioButton android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false"/>
</com.utils.ui.widget.CheckableLinearLayout>
Added to settings.xml
<com.utils.ui.preference.IconTypePreference
android:key="icon_type"
android:defaultValue="type_b"
android:title="#string/icon_type_preference_title"/>
EDIT
There is a bug in CheckableLinearLayout.java
Replace the getCheckable method with this:
private Checkable getCheckable(ViewGroup viewGroup) {
View v;
int childCount = viewGroup.getChildCount();
for (int i = 0; i < childCount; ++i) {
v = viewGroup.getChildAt(i);
if (v instanceof Checkable) {
return (Checkable)v;
} else if (v instanceof ViewGroup) {
Checkable result = getCheckable((ViewGroup)v);
if (result != null) {
return result;
}
}
}
return null;
}
Found the solution to the problem.
The problem was in the getView method of the adapter:
I changed
convertView.setClickable(true);
to
convertView.setClickable(false);
First of all, I know that this was asked several time, but on newer android versions it looks like that the suggested solutions doesn't work.
I need that my spinner call OnItemSelected even when the user select the same item twice.
I've found this class that should do the trick:
public class NDSpinner extends Spinner {
private int lastSelected = 0;
private static Method s_pSelectionChangedMethod = null;
static {
try {
Class noparams[] = {};
Class targetClass = AdapterView.class;
s_pSelectionChangedMethod = targetClass.getDeclaredMethod("selectionChanged", noparams);
if (s_pSelectionChangedMethod != null) {
s_pSelectionChangedMethod.setAccessible(true);
}
} catch( Exception e ) {
Log.e("Custom spinner, reflection bug:", e.getMessage());
throw new RuntimeException(e);
}
}
public NDSpinner(Context context) {
super(context);
}
public NDSpinner(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NDSpinner(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if(this.lastSelected == this.getSelectedItemPosition())
testReflectionForSelectionChanged();
if(!changed)
lastSelected = this.getSelectedItemPosition();
super.onLayout(changed, l, t, r, b);
}
public void testReflectionForSelectionChanged() {
try {
Class noparams[] = {};
s_pSelectionChangedMethod.invoke(this, noparams);
} catch (Exception e) {
Log.e("Custom spinner, reflection bug: ", e.getMessage());
e.printStackTrace();
}
}
#Override
public void onClick(DialogInterface dialog, int which) {
super.onClick(dialog, which);
}
}
This infact works, but it has a bug: it call twice the item the first time :(
Can anybody tell me how can I solve this ?
Thanks mates.
I've solved using this class:
public class NDSpinner extends Spinner {
public NDSpinner(Context context)
{ super(context); }
public NDSpinner(Context context, AttributeSet attrs)
{ super(context, attrs); }
public NDSpinner(Context context, AttributeSet attrs, int defStyle)
{ super(context, attrs, defStyle); }
#Override public void
setSelection(int position, boolean animate)
{
boolean sameSelected = position == getSelectedItemPosition();
super.setSelection(position, animate);
if (sameSelected) {
// Spinner does not call the OnItemSelectedListener if the same item is selected, so do it manually now
getOnItemSelectedListener().onItemSelected(this, getSelectedView(), position, getSelectedItemId());
}
}
#Override public void
setSelection(int position)
{
boolean sameSelected = position == getSelectedItemPosition();
super.setSelection(position);
if (sameSelected) {
// Spinner does not call the OnItemSelectedListener if the same item is selected, so do it manually now
getOnItemSelectedListener().onItemSelected(this, getSelectedView(), position, getSelectedItemId());
}
}
}
Thanks anyway :)
For me, I extended AppCompatSpinner.
Also if your Spinneris in XML for layout, remember to change your
<Spinner...
to
<com.example.util.NDSpinner...
First of all, I know that this was asked several time, but on newer android versions it looks like that the suggested solutions doesn't work.
I need that my spinner call OnItemSelected even when the user select the same item twice.
I've found this class that should do the trick:
public class NDSpinner extends Spinner {
private int lastSelected = 0;
private static Method s_pSelectionChangedMethod = null;
static {
try {
Class noparams[] = {};
Class targetClass = AdapterView.class;
s_pSelectionChangedMethod = targetClass.getDeclaredMethod("selectionChanged", noparams);
if (s_pSelectionChangedMethod != null) {
s_pSelectionChangedMethod.setAccessible(true);
}
} catch( Exception e ) {
Log.e("Custom spinner, reflection bug:", e.getMessage());
throw new RuntimeException(e);
}
}
public NDSpinner(Context context) {
super(context);
}
public NDSpinner(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NDSpinner(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if(this.lastSelected == this.getSelectedItemPosition())
testReflectionForSelectionChanged();
if(!changed)
lastSelected = this.getSelectedItemPosition();
super.onLayout(changed, l, t, r, b);
}
public void testReflectionForSelectionChanged() {
try {
Class noparams[] = {};
s_pSelectionChangedMethod.invoke(this, noparams);
} catch (Exception e) {
Log.e("Custom spinner, reflection bug: ", e.getMessage());
e.printStackTrace();
}
}
#Override
public void onClick(DialogInterface dialog, int which) {
super.onClick(dialog, which);
}
}
This infact works, but it has a bug: it call twice the item the first time :(
Can anybody tell me how can I solve this ?
Thanks mates.
I've solved using this class:
public class NDSpinner extends Spinner {
public NDSpinner(Context context)
{ super(context); }
public NDSpinner(Context context, AttributeSet attrs)
{ super(context, attrs); }
public NDSpinner(Context context, AttributeSet attrs, int defStyle)
{ super(context, attrs, defStyle); }
#Override public void
setSelection(int position, boolean animate)
{
boolean sameSelected = position == getSelectedItemPosition();
super.setSelection(position, animate);
if (sameSelected) {
// Spinner does not call the OnItemSelectedListener if the same item is selected, so do it manually now
getOnItemSelectedListener().onItemSelected(this, getSelectedView(), position, getSelectedItemId());
}
}
#Override public void
setSelection(int position)
{
boolean sameSelected = position == getSelectedItemPosition();
super.setSelection(position);
if (sameSelected) {
// Spinner does not call the OnItemSelectedListener if the same item is selected, so do it manually now
getOnItemSelectedListener().onItemSelected(this, getSelectedView(), position, getSelectedItemId());
}
}
}
Thanks anyway :)
For me, I extended AppCompatSpinner.
Also if your Spinneris in XML for layout, remember to change your
<Spinner...
to
<com.example.util.NDSpinner...
I use dropdown spinner with cursor adapter. It contains e.g 1 - 100 items.
I select e.g. item 50. Item is selected. Next time when I open spinner first visible row is item 50. How can I achieve that when I open spinner it will focus to first item/first visible item will be item 1?
I mean like autoscroll up in the list, so first visible item in dropdown is 1st one and not selected one.
You can make the Spinner do what you want by extending it and overriding the two methods that are responsible for setup/showing the list of values:
public class CustomSpinnerSelection extends Spinner {
private boolean mToggleFlag = true;
public CustomSpinnerSelection(Context context, AttributeSet attrs,
int defStyle, int mode) {
super(context, attrs, defStyle, mode);
}
public CustomSpinnerSelection(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
}
public CustomSpinnerSelection(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomSpinnerSelection(Context context, int mode) {
super(context, mode);
}
public CustomSpinnerSelection(Context context) {
super(context);
}
#Override
public int getSelectedItemPosition() {
// this toggle is required because this method will get called in other
// places too, the most important being called for the
// OnItemSelectedListener
if (!mToggleFlag) {
return 0; // get us to the first element
}
return super.getSelectedItemPosition();
}
#Override
public boolean performClick() {
// this method shows the list of elements from which to select one.
// we have to make the getSelectedItemPosition to return 0 so you can
// fool the Spinner and let it think that the selected item is the first
// element
mToggleFlag = false;
boolean result = super.performClick();
mToggleFlag = true;
return result;
}
}
It should work just fine for what you want to do.
You can set the selection of a Spinner to the first item like this:
yourspinner.setSelection(0);
You might want to do this in the onStart() method.
This short of code will do the work for you.
int prevSelection=0;
spSunFrom = (Spinner) findViewById(R.id.spTimeFromSun);
spSunFrom.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
prevSelection = spSunFrom.getSelectedItemPosition();
spSunFrom.setSelection(0);
return false;
}
});
spSunFrom.setOnItemSelectedListener(new OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> arg0, View arg1,
int arg2, long arg3) {
if(arg2==0)
spSunFrom.setSelection(prevSelection);
prevSelection = arg2;
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
spSunFrom.setSelection(prevSelection);
}
});