Android Spinner OnItemSelected not called with the same item - android

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...

Related

Android Spinner setOnItemSelectedListener

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());
}
}
}

How to do actions when scroll view reached bottom end?

I have an Activity with a scroll view and 2 buttons, When open this activity both buttons are disabled. What I want is, when I reach the end of the scroll view, enable both buttons to user to accept or decline the content. How can I do this in simple way.
Button before enabled
Thanks in advance.
I have done this things with webView here is my code, hope it will help you.
webView.setOnScrollChangedCallback(new ObservableWebView.OnScrollChangedCallback() {
#Override
public void onScroll(int l, int t) {
int tek = (int) Math.floor(webView.getContentHeight() * webView.getScale());
if (tek - webView.getScrollY() <= webView.getHeight() + 5) {
// enable your button
}
}
});
this is the class
public class ObservableWebView extends WebView
{
private OnScrollChangedCallback mOnScrollChangedCallback;
public ObservableWebView(final Context context)
{
super(context);
}
public ObservableWebView(final Context context, final AttributeSet attrs)
{
super(context, attrs);
}
public ObservableWebView(final Context context, final AttributeSet attrs, final int defStyle)
{
super(context, attrs, defStyle);
}
#Override
protected void onScrollChanged(final int l, final int t, final int oldl, final int oldt)
{
super.onScrollChanged(l, t, oldl, oldt);
if(mOnScrollChangedCallback != null) mOnScrollChangedCallback.onScroll(l, t);
}
public OnScrollChangedCallback getOnScrollChangedCallback()
{
return mOnScrollChangedCallback;
}
public void setOnScrollChangedCallback(final OnScrollChangedCallback onScrollChangedCallback)
{
mOnScrollChangedCallback = onScrollChangedCallback;
}
/**
* Impliment in the activity/fragment/view that you want to listen to the webview
*/
public static interface OnScrollChangedCallback
{
public void onScroll(int l, int t);
}
}
happy coding.

Custom layout for ListPreference

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);

How to respond to selection of a value of Spinner multiple times instead of one time? [duplicate]

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...

Android numberpicker, never pass from OnValueChangedListener breakpoint

I extended the NumberPicker class, I overrided to the setOnValueChangedListener but when I debug the code and I click on the plus button of the numberpicker, it never pass in my breakpoint inside the method setOnValueChangedListener.
Something is wrong?
#TargetApi(Build.VERSION_CODES.HONEYCOMB)//For backward-compability
public class NumberPickerCustom extends NumberPicker
{
private int clickNumber = 0;
public NumberPickerCustom(Context context) {
super(context);
}
public NumberPickerCustom(Context context, AttributeSet attrs) {
super(context, attrs);
processAttributeSet(attrs);
}
public NumberPickerCustom(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
processAttributeSet(attrs);
}
private void processAttributeSet(AttributeSet attrs) {
//This method reads the parameters given in the xml file and sets the properties according to it
this.setMinValue(attrs.getAttributeIntValue(null, "min", 0));
this.setMaxValue(attrs.getAttributeIntValue(null, "max", 0));
this.setValue(attrs.getAttributeIntValue(null, "value", 0));
}
#Override
public void setOnValueChangedListener(
OnValueChangeListener onValueChangedListener)
{
super.setOnValueChangedListener(onValueChangedListener);
if (onValueChangedListener==null)
{
onValueChangedListener = new OnValueChangeListener() {
#Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal)
{
clickNumber++;
if (clickNumber>10)
{
clickNumber = -1000;
Toast.makeText(getContext(), "Clicca sul numero centrale per inserire direttamente un valore", Toast.LENGTH_SHORT).show();
}
}
};
}
}
}
You can initializze your custom number picker
View rootView = inflater.inflate(R.layout.fragment_random_block, container, false);
NumberPickerCustom np = (NumberPickerCustom) rootView.findViewById(R.id.numberPickerCustom);
np.setOnValueChangedListener(this);
Make sure your class implements
implements OnValueChangeListener
Then
#Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
Toast.makeText(MainActivity.this, "Clicca sul numero centrale per inserire direttamente un valore", Toast.LENGTH_SHORT).show();
}
}
Snap shot:
When you the value changes you get to see the toast modify the same according to your requirement.
Edit :
Change your custom NumberPicker as below
public class NumberPickerCustom extends NumberPicker implements OnValueChangeListener
{
public NumberPickerCustom(Context context) {
super(context);
}
public NumberPickerCustom(Context context, AttributeSet attrs) {
super(context, attrs);
processAttributeSet(attrs);
}
public NumberPickerCustom(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
processAttributeSet(attrs);
}
private void processAttributeSet(AttributeSet attrs) {
//This method reads the parameters given in the xml file and sets the properties according to it
this.setMinValue(attrs.getAttributeIntValue(null, "min", 0));
this.setMaxValue(attrs.getAttributeIntValue(null, "max", 0));
this.setValue(attrs.getAttributeIntValue(null, "value", 0));
this.setOnValueChangedListener(this);
}
#Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
Toast.makeText(getContext(), "New Value is"+newVal, Toast.LENGTH_SHORT).show();
}
}
Snap shot

Categories

Resources