I want to fire a event when the same item is selected in spinner. Method
#Override
public void onItemSelected(AdapterView<?> parent, View arg1, int position,
long arg3) {
}
is called only when we different selection is made. My Purpose is to display a toast when any item is selected either the same item is reselected or different selection is made.
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
above method does not solve my problem.
i have found that old selection is kept at variable called mOldSelectedPosition in the hierarcy of the spinner. Spinner is using this value to check if the same item selected or not , and if it is the same , it ignores. If we dont wanna ignore this What i did is some dirty code using reflection.
package com.aradiom.amc.nativecomponents;
import java.lang.reflect.Field;
import android.content.Context;
import android.util.Log;
import android.widget.Spinner;
public class SpinnerTrigger extends Spinner {
public SpinnerTrigger(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
#Override
public void setSelection(int position, boolean animate) {
ignoreOldSelectionByReflection();
super.setSelection(position, animate);
}
private void ignoreOldSelectionByReflection() {
try {
Class<?> c = this.getClass().getSuperclass().getSuperclass().getSuperclass();
Field reqField = c.getDeclaredField("mOldSelectedPosition");
reqField.setAccessible(true);
reqField.setInt(this, -1);
} catch (Exception e) {
Log.d("Exception Private", "ex", e);
// TODO: handle exception
}
}
#Override
public void setSelection(int position) {
ignoreOldSelectionByReflection();
super.setSelection(position);
}
}
This class will always invalidate the oldselection value , so that every time on click event gets triggered.
It may not be perfect solution. Use with caution. :)
Hopefully this help. I tried and it works
/** Spinner extension that calls onItemSelected even when the selection is the same as its previous value */
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());
}
}
}
Since my reputation is not high enough to comment directly on #Suat 's answer, I tried that method, it works like charm, but I'm not clear what the side effects could be.
Something I want to add is, additional constructors should be added to avoid errors.
public SpinnerTrigger(Context context, AttributeSet attrs, int defStyle)
{ super(context, attrs, defStyle); }
public SpinnerTrigger(Context context, AttributeSet attrs){
super(context,attrs);
}
You can add a method name on your item selected METHOD
Spinner `Spinner1`=(Spinner)findViewById(R.id.`declareid`)
oBject has been declared for spinner
#Override
public void onItemSelected(AdapterView<?> parent, View arg1, int position,
long arg3)
{
ItemOnChange();
}
private void ItemOnChange() {
if(Spinner1.getSelectedItemPosition()>0){
pd=ProgressDialog.show(this,"","Loading, Please wait .. ",true);
final int spinner=Spinner1.getSelectedItemPosition();
final Handler ThreadCallback=new Handler();
final Runnable runInCityThread=new Runnable(){
public void run(){
fnBindspimmer2();
pd.dismiss();
}
};
new Thread(){
#Override public void run(){
Spinner2values();
ThreadCallback.post(runInCityThread);
}
}.start();
}
}
use click listener to fulfill your requirement. as direct click listener on spinner doesn't supported so make a class extend spinner and over ride on click method and in this method do what you want to do.
Related
I disable swipe the ViewPager with TabLayout as below:
public class NonScrollableViewPager extends ViewPager {
public NonScrollableViewPager(Context context) {
super(context);
init(context, null);
}
public NonScrollableViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
}
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
// Never allow swiping to switch between pages
return false;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
// Never allow swiping to switch between pages
return false;
}
}
How to prevent other tabs clickable when select one of tabs, then computation complected then enable the clickable. ViewPager.setClickable(false) and setEnabled() don't work
disable clickable
// do something
enable clickable
How to do that?
I am assuming that you are using TabLayout along with ViewPager. So, you need to implement as follows
LinearLayout tabStrip = ((LinearLayout) your_tab_layout.getChildAt(0));
for(int i = 0; i < tabStrip.getChildCount(); i++) {
tabStrip.getChildAt(i).setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
}
For API 24 and above
your_tab_layout.clearOnTabSelectedListeners();
Hope this helps
I've created a custom spinner, because again and again, I found that I wanted to make sure that the onItemSelectedListener wasn't triggered when I set my Spinner's initial selection or set a new custom adapter. I only want it triggered when a user actually selects an item.
But for some reason (I'm at a complete loss as to why), my custom spinner doesn't respond to touch events. It's as if it's disabled, even though I've debugged and seen that it's perfectly enabled. But for some reason, my little spinner won't open. Can anyone help me understand why?
Here's the xml:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginTop="#dimen/default_margin"
android:orientation="horizontal">
<my.app.custom.view.MySpinner
android:id="#+id/dog_or_cat_toggle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:layout_margin="0dp"
android:textAlignment="center"
android:gravity="center_vertical|center"
android:padding="0dp"
android:entries="#array/dog_or_cat"
android:spinnerMode="dropdown"
android:background="#drawable/top_to_bottom_gray_gradient"/>
...
</LinearLayout>
And my Custom Spinner:
/* A Spinner dispatches an onItemSelected event when the View is initialized, before the user ever makes a selection.
* This class allows listeners for just the initial selection, just user selections, or both. */
public class MySpinner extends Spinner {
private boolean initialized = false;
private OnItemSelectedListener onItemSelectionInitializedListener;
private OnItemSelectedListener onItemSelectedByUserListener;
private OnItemSelectedListener onItemSelectedListener;
public MySpinner(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MySpinner(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public MySpinner(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
this.initializeMySpinner();
}
public void setOnItemSelectionInitializedListener(OnItemSelectedListener onItemSelectionInitializedListener) {
this.onItemSelectionInitializedListener = onItemSelectionInitializedListener;
}
public void setOnItemSelectedByUserListener(OnItemSelectedListener onItemSelectedByUserListener) {
this.onItemSelectedByUserListener = onItemSelectedByUserListener;
}
#Override
public void setOnItemSelectedListener(OnItemSelectedListener onItemSelectedListener) {
this.onItemSelectedListener = onItemSelectedListener;
}
#Override
public void setAdapter(SpinnerAdapter adapter) {
this.initialized = false;
super.setAdapter(adapter);
}
private void initializeMySpinner() {
super.setOnItemSelectedListener(new OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if(!initialized) {
if(onItemSelectionInitializedListener != null) onItemSelectionInitializedListener.onItemSelected(parent, view, position, id);
if(onItemSelectedListener != null) onItemSelectedListener.onItemSelected(parent, view, position, id);
initialized = true;
} else {
if(onItemSelectedListener != null) onItemSelectedListener.onItemSelected(parent, view, position, id);
if(onItemSelectedByUserListener != null) onItemSelectedByUserListener.onItemSelected(parent, view, position, id);
}
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
if(!initialized) {
if(onItemSelectionInitializedListener != null) onItemSelectionInitializedListener.onNothingSelected(parent);
if(onItemSelectedListener != null) onItemSelectedListener.onNothingSelected(parent);
initialized = true;
} else {
if(onItemSelectedListener != null) onItemSelectedListener.onNothingSelected(parent);
if(onItemSelectedByUserListener != null) onItemSelectedByUserListener.onNothingSelected(parent);
}
}
});
}
}
Don't call one constructor from another. Instead, call super() constructor from each one.
I have faced the same issue some time back and this trick worked, but I'm not sure about the reason.
I'm extending the EditText class in android to incorporate additional functionality one of which is to display a dialog when clicked. I want the behaviour to be portable and hence self contained.
However setting onClickListener to itself (this) as parameter has no effect and the function onClick(View) is never called.
public class TimePickerEditText extends EditText implements View.OnClickListener, TimePickerDialog.OnTimeSetListener {
private Calendar today;
private TimePickerDialog timePickerDialog;
public TimePickerEditText(Context context) {
super(context);
postInstantiateSetup();
}
public TimePickerEditText(Context context, AttributeSet attrs) {
super(context, attrs);
postInstantiateSetup();
}
public TimePickerEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
postInstantiateSetup();
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
postInstantiateSetup();
}
public void postInstantiateSetup()
{
setOnClickListener(this);
today = Calendar.getInstance();
onTimeSet(null,today.get(Calendar.HOUR_OF_DAY),today.get(Calendar.MINUTE));
}
#Override
public void onClick(View view) {
if(timePickerDialog == null) {
timePickerDialog = new TimePickerDialog(getContext(), this, 20, 0, true);
}
timePickerDialog.show();
}
#Override
public void onTimeSet(TimePicker timePicker, int hours, int minutes) {
String hoursString = ""+hours;
if(hours<10)
hoursString="0"+hoursString;
String minutesString = ""+minutes;
if(minutes<10)
minutesString="0"+minutesString;
this.setText(hoursString+":"+minutesString);
}
}
I have two spinners, such that my second spinner changes options that it can offer according to the item selected in the first spinner. Easy?
Example: If I select 'a' in main spinner, the sub spinner should show 'a1' as option. If I select 'b' in main spinner, the sub spinner should show 'b1','b2' as options. If I select 'c' in main spinner, the sub spinner should show 'c1','c2','c3' as options.
I use a library called SearchableSpinner but that does not matter as it works just like the Android spinner.
public class PostComplaint extends AppCompatActivity {
String[] problems_main = {"a","b","c"};
String[][] problems_sub = {{"a1"},{"b1","b2"},{"c1","c2","c3"}};
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_post_complaint);
spinner_main = (SearchableSpinner)findViewById(R.id.spinner_main);
spinner_sub = (SearchableSpinner) findViewById(R.id.spinner_sub);
ArrayAdapter<String> spinnerAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, problems_main);
spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner_main.setAdapter(spinnerAdapter);
spinnerAdapter.notifyDataSetChanged();
spinner_main.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
setSubSpinner(position);
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
Toast.makeText(PostComplaint.this, "Nothing selected", Toast.LENGTH_SHORT).show();
}
});
}
void setSubSpinner(int i){
String[] myArray = problems_sub[i]; //Note: problems_sub is a two dimensional array
ArrayAdapter<String> spinnerAdapter_sub = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, myArray);
spinnerAdapter_sub.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner_sub.setAdapter(spinnerAdapter_sub);
spinnerAdapter_sub.notifyDataSetChanged();
}
Problem: Whichever item I click on the main spinner for the first time, according to that the sub spinner is selected. Then if I change the main spinner, the sub spinner is not changing.
The question is open for suggestions. Comment if it is not understandable.
The error is coming because of the following function in the SearchableSpinner Class:
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
ArrayAdapter adapter = (ArrayAdapter) getAdapter();
if (null != adapter) {
if (_items.size() == 0) {
for (int i = 0; i < adapter.getCount(); i++) {
_items.add(adapter.getItem(i));
}
}
SearchableListDialog searchableListDialog = SearchableListDialog.newInstance
(_items);
searchableListDialog.setOnSearchableItemClickListener(this);
searchableListDialog.show(((Activity) _context).getFragmentManager(), "TAG");
}
}
return true;
}
The condition if(_items.size() == 0) becomes true only the first time you click on the sub spinner and hence it gets initialized correctly and you will see correct values. However, once you have clicked on the sub spinner, _item.size() will never be zero and thus, the updated sub spinner values will never be rendered.
I suggest you use the default Android Spinner or fork the repository and fix the error and use the same.
EDIT
You can try using this class:
import android.app.Activity;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import com.toptoche.searchablespinnerlibrary.SearchableListDialog;
import java.util.ArrayList;
import java.util.List;
public class CustomSearchableSpinner extends Spinner implements View.OnTouchListener,
SearchableListDialog.SearchableItem {
private Context _context;
private List _items;
private boolean isDataSetChanged;
public CustomSearchableSpinner(Context context) {
super(context);
this._context = context;
this.isDataSetChanged = true;
init();
}
public CustomSearchableSpinner(Context context, AttributeSet attrs) {
super(context, attrs);
this._context = context;
this.isDataSetChanged = true;
init();
}
public CustomSearchableSpinner(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this._context = context;
this.isDataSetChanged = true;
init();
}
private void init() {
_items = new ArrayList();
setOnTouchListener(this);
}
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
ArrayAdapter adapter = (ArrayAdapter) getAdapter();
if (null != adapter) {
if (isDataSetChanged) {
if(_items.size() != 0) {
_items = new ArrayList();
}
for (int i = 0; i < adapter.getCount(); i++) {
_items.add(adapter.getItem(i));
}
isDataSetChanged = false;
}
SearchableListDialog searchableListDialog = SearchableListDialog.newInstance
(_items);
searchableListDialog.setOnSearchableItemClickListener(this);
searchableListDialog.show(((Activity) _context).getFragmentManager(), "TAG");
}
}
return true;
}
#Override
public void onSearchableItemClicked(Object item, int position) {
setSelection(_items.indexOf(item));
}
public void notifyDataChanged(Boolean hasDataChanged) {
this.isDataSetChanged = hasDataChanged;
}
}
Also, update your layout file and PostComplaint Class to use CustomSearchableSpinner in place of Searchable Spinner. It may not be the best approach, but it works.
EDIT 2
You will need to call spinnerAdapter_sub.notifyDataChanged(true) after you call spinnerAdapter_sub.notifyDataSetChanged();.
I'm trying to Horizontal Slider Menu in Android(like Facebook).
I want only my container View to be able to capture mouse touch event.
I have tried setEnable(false) all of child elements of my container view. But It cause the view not to capture touch event.
public void ChangeMenuVisibility() {
int menuWidth = menu.getMeasuredWidth();
// Ensure menu is visible
menu.setVisibility(View.VISIBLE);
int left = !menuOut ? 0 : menuWidth;
container.smoothScrollTo(left, 0);
menuOut = !menuOut;
ViewUtils.enableDisableViewGroup(
(ViewGroup) window.findViewById(R.id.main_content), !menuOut);
window.findViewById(R.id.main_content).setEnabled(true);
}
[ViewUtils.java]
public static void enableDisableViewGroup(ViewGroup viewGroup,
boolean enabled) {
int childCount = viewGroup.getChildCount();
for (int i = 0; i < childCount; i++) {
View view = viewGroup.getChildAt(i);
view.setEnabled(enabled);
if (view instanceof ViewGroup) {
enableDisableViewGroup((ViewGroup) view, enabled);
}
}
}
What strategy should I follow to accomplish this.
Any help will be appreciated.
Override View.onInterceptTouchEvent() in the ViewGroup, don't call super.onInterceptTouchEvent() and return true. This causes the touch events to not be passed down the hierarchy (to the children of the ViewGroup).
I have resolved this problem the inspiration of #nmw's answer.
You should extend your View group (I prefer to use LinearLayout).
For the child elements neglect the mouse touch event. You have to implement onInterceptTouchEvent method.
This is example layout for solving this problem:
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.LinearLayout;
public class MyLinearLayout extends LinearLayout {
public MyLinearLayout(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public MyLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
boolean mChildCanCaptureTouchEvent = true;
/**
* #return the mChildCanCaptureTouchEvent
*/
public boolean ChildCanCaptureTouchEvent() {
return mChildCanCaptureTouchEvent;
}
/**
* #param mChildCanCaptureTouchEvent
* the mChildCanCaptureTouchEvent to set
*/
public void ChildCanCaptureTouchEvent(boolean mChildCanCaptureTouchEvent) {
this.mChildCanCaptureTouchEvent = mChildCanCaptureTouchEvent;
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (ev.getAction() != MotionEvent.ACTION_MOVE) {
return true;
}
if (!mChildCanCaptureTouchEvent)
return true;
return super.onInterceptTouchEvent(ev);
}
}