I have created a custom dialog and a layout xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Tap Me"
android:onClick="dialogClicked" />
</LinearLayout>
In the dialog class I've implemented the method "dialogClicked(View v)":
public class TestDialog extends Dialog {
public TestDialog(final Context context)
{
super(context);
}
#Override
protected void onCreate(final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.dialog);
}
public void dialogClicked(final View view)
{
System.out.println("clicked");
}
}
When I tap the button I get a NoSuchMethodException 'dialogClicked'. Setting the onClick handler in layout xml works fine for activities, but not in dialogs. Any ideas? What I'm doing wrong?
Define the method (dialogClicked) in Activity.
And modify TestDialog like the following code:
public class TestDialog extends Dialog {
Context mContext;
public TestDialog(final Context context)
{
super(context);
mContext=context;
}
#Override
protected void onCreate(final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
LinearLayout ll=(LinearLayout) LayoutInflater.from(mContext).inflate(R.layout.dialog, null);
setContentView(ll);
}
}
I think it works :)
I think the issue is one of scope. I'm not sure how'd you address this in xml, but essentially the dialogueClicked method in your layout xml doesn't know where to find the method you've defined in the dialog class.
The standard approach i've seen to bind buttons in custom layouts is as follows.
implement the OnClickListener class
Bind the buttons click event to the dialog class
Switch out the buttons in the onClick button based on id. You'd need to add an id to your button.
.
public class TestDialog extends Dialog implements android.view.View.OnClickListener
{
protected void onCreate(final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.dialog);
((Button)findViewById(R.id.dialog_btn_mybutton)).setOnClickListener(this);
}
public void onClick(View view)
{
switch (view.getId())
{
case R.id.dialog_btn_mybutton:
//do stuff
// dismiss();
// cancel etc.
break;
}
}
}
Hope that helps. Would still be interested in knowing if there was a solution to using xml onClick to bind to the method. Perhaps an additional argument in the setContentView? something r'other.
I've found the following code in the View.java source:
public void onClick(View v) {
if (mHandler == null) {
try {
mHandler = getContext().getClass().getMethod(handlerName,
View.class);
...
-> The views uses its context to resolve the onclick handler method.
Noew the following code from Dialog.java source:
public Dialog(Context context, int theme) {
mContext = new ContextThemeWrapper(context, theme == 0 ? com.android.internal.R.style.Theme_Dialog : theme);
...
In the constructor of the dialog an instance of ContextThemeWrapper gets created and set as context. This instance is neither the custom dialog class, nor the calling activity, which can be the place for implementing the handler method. Therefore views are not able to find the onclick handler method.
But I have to use the onclick XML attribut. Any workarounds available?
Dialogs need the signature
dialogClicked(DialogInterface dialog, int id) { ... }
android:onClick="method" is pretty cool, but it doesn't work on Android 1.5 so I am avoiding for some time.
An easy workaround:
Make your Dialog an Activity and use android:theme="#android:style/Theme.Dialog" in you AndroidManifest.
Following on from Jett Hsieh's post, I've implemented my dialogs slightly differently using showDialog and dismissDialog, but the fundamentals of getting the android:onClick working have been the same, my example code is below for future reference.
public class ExampleActivity extends Activity {
static final int DIALOG_DISCLAIMER = 0;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
showDialog(DIALOG_DISCLAIMER);
}
protected Dialog onCreateDialog(int id)
{
Dialog dialog;
switch(id)
{
case DIALOG_DISCLAIMER:
dialog = new Dialog(this);
dialog.setContentView(R.layout.main_disclaimer);
LinearLayout ll = (LinearLayout) LayoutInflater.from(this).inflate(R.layout.main_disclaimer, null);
dialog.setContentView(ll);
break;
default:
dialog = null;
}
return dialog;
}
public void onClick(View v)
{
switch(v.getId())
{
case R.id.maindisclaimer_button_accept:
dismissDialog(DIALOG_DISCLAIMER);
break;
}
}
}
And the layout file:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/linearLayout1"
android:padding="10dp"
android:orientation="vertical"
android:background="#drawable/roundedcorners">
<Button
android:id="#+id/maindisclaimer_button_accept"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="#string/string_accept"
android:onClick="onClick" >
</Button>
</LinearLayout>
Try to define that method (dialogClicked) in the activity and not in the dialog.
It might use reflection so if you use different activities just write that method in each activity that might show that dialog
A dialog is always created and displayed as part of an Activity. According to Android References:
If you decide to create a dialog outside of the onCreateDialog() method,
it will not be attached to an Activity. You can, however,
attach it to an Activity with setOwnerActivity(Activity).
Also, are you passing the object returned by getApplicationContext(); to the constructor of TestDialog?
system looks for the method in the where the layout has been inflated from, or in the activity class to which the xml was set as content.
Related
MainActivity shows a viewpager
so there are 3 layout files:activity_main.xml、card1.xml and card2.xml
Now I want to get view from card1.xml and set the listener.
what should I do?
I tried using this:
LayoutInflater layout=this.getLayoutInflater();
View view=layout.inflate(R.layout.card1, null);
Button b=(Button)view.findViewById(R.id.b);
then set OnClickListener:
b.setOnClickListener(new MyClickListener(0));
but useless.
In your card1.xml, you can add a onClick attribute, and just provide the method name as the attribute's value, like this:
<Button android:id="#+id/mybutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Click me!"
android:onClick="myMethod" />
Now in you MainActivity.java file, create a public method with return type as void, and which takes in a View parameter, like this:
public void myMethod(View v) {
// do your thing here
}
You can read more about it here.
public class MyClickListener implements OnClickListener {
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.your_btn_id:
// your code
break;
}
}
}
another way is you can add button click listener in your card1.xml fragment class.
I'm developing a simple application in which youb have different spots placed on google map.
When I click on a spot I get its details which are displayed in a GridViewPager.
For now my application is based on the GridViewPager sample available with the sdk.
Here is my layout for the spot details (nothing fancy)
<android.support.wearable.view.GridViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:keepScreenOn="true"/>
My problem now is that I'm not able to detect a Click event on a card.
I've tried this but it doesn't work.
public class DetailsActivity extends Activity implements GridViewPager.OnClickListener {
#Override
public void onClick(View v) {
}
I've also tried View.OnClickListener.
Have any idea ?
There are two issues here. First, if you really want to make the GridViewPager clickable, you need to tell it to listen for click events - just implementing the OnClickListener interface isn't sufficient. So you need to do something like this:
public class DetailsActivity ... {
#Override
public void onCreate(Bundle savedInstanceState) {
...
GridViewPager pager = (GridViewPager)findViewById(R.id.pager);
pager.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// put your onClick logic here
}
});
...
}
}
That being said, however, based on your description it sounds like what you actually want is to set up click handlers on individual pages within the grid, not on the entire grid. If so, then you'll need to do something similar but in each page's Fragment class. For example:
public class MyPageFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View result = inflater.inflate(...);
result.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// put your onClick logic here
}
});
...
return result;
}
}
Note: if you are using CardFragments in your GridViewPager, then you would probably set the OnClickListener in your onCreateContentView override. Otherwise, the above Fragment-based example should apply.
On Android here is for example an excellent code fragment,
showing how to achieve five buttons on a dialog fragment...
android DialogFragment android:onClick="buttonCancel" causes IllegalStateException could not find a method
in your DialogFragment, you have to setOnClickListener(this) for all of your buttons/imageviews etc.
Then you implement View.OnClickListener and have a routine like this...
public void onClick(View v)
{
Utils.Log("Fucking 'A' sort of... ");
switch (v.getId())
{
case R.id.postfragment_send:
break;
etc etc etc
default:
break;
}
}
That's all fantastic. BUT.
Over in my main activity, where I have a ListView. The custom cells have five buttons. Very simply, in the main activity, I have five routines named whatever I like...
public void clickedComments(View v)
{
int position = feed.getPositionForView(v);
...etc etc
}
public void clickedExplosions(View v)
{
int position = feed.getPositionForView(v);
...etc etc
}
public void clickedTanks(View v)
{
int position = feed.getPositionForView(v);
...etc etc
}
Then you just do this which is unbelievably easy ("screw Xcode!") ...
Amazing!
My question, why can't I use the 'onClick system' in dialog fragments?
What am I doing wrong? Can an android expert explain what the fundamental difference is between the two? For the record my projects are 4.1+ only.
Thanks!!
Here I am pasting in a full example of a fragment, using the first method described above.
public class HappyPopupFragment extends DialogFragment implements View.OnClickListener
{
#Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{
Dialog dialog = super.onCreateDialog(savedInstanceState);
dialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
dialog.getWindow().setGravity(Gravity.CENTER_HORIZONTAL | Gravity.TOP);
dialog.getWindow().setBackgroundDrawableResource(android.R.color.transparent);
return dialog;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.happy_popup, container);
_setupButtons(view);
return view;
}
public void onClick(View v)
{
Utils.Log("Fucking 'A' sort of... ");
switch (v.getId())
{
case R.id.button_a:
Utils.Log("tanks !!");
break;
case R.id.button_b:
Utils.Log("bombs !!");
break;
case R.id.button_c:
Utils.Log("guns !!");
break;
case R.id.button_d:
Utils.Log("ammo !!");
break;
default:
break;
}
}
private void _setupButtons(View view)
{
((ImageView)view.findViewById(R.id.button_a)).setOnClickListener(this);
((ImageView)view.findViewById(R.id.button_b)).setOnClickListener(this);
((ImageView)view.findViewById(R.id.button_c)).setOnClickListener(this);
((TextView)view.findViewById(R.id.button_d)).setOnClickListener(this);
}
}
that's actually a pretty simple answer, but you have to start it by remembering that Android 1.0 there were no Fragments.
First let's see what an activity really is:
java.lang.Object
↳ android.content.Context
↳ android.content.ContextWrapper
↳ android.view.ContextThemeWrapper
↳ android.app.Activity
An object that extend Context, that's what it is.
So, when you inflate the XML layout, that method inflate is doing stuff like creating and setting up the views like that:
View v = new View(context) // see the context here ?
then when you set on your XML onClick:commentsClick for example, what is happening when you click is:
getContext().commentsClick(View.this); // look, the context again
so let's analyse that:
The XML onClick tries to call back to the context, meaning, call back to the activity that inflated it. See that the IllegalStateException message says that it cannot find the method? Well, because it's not in the activity. Probably if you put commentsClick in the Activity that is creating the DialogFragment, it will work, but that's just bad O.O., right?
The thing with the XML onClick was a nice facilitator to avoid on the huge switch(int) case, but it is a solution that simply does not scale to other classes that might inflate layouts, such as Fragments.
It's just a fact of Android DialogFragment API. Callback methods defined in a fragment XML layout are called in the Activity which contains this fragment. It`s more simple than you mean because in previous Android API-s such "XML defined" callbacks were called in activities also.
(Transferred from my comments as it strikes me as an answer to the question of topic. Perhaps this will be more convenient to future readers of this topic.)
you can use onClickListener, on each View and its subclasses.
setOnClickListener takes as parameter an instance of the class that implements View.OnclickListener.
If you have an error on setOnClickListener(this) it means that the object this refers is an object of an class that does not implements View.OnClickListener
In other words...
Here's how to make onClickListener work for custom cells in custom list views in custom dialog fragments!
in the ADAPTER class (1) for your list view, you'll have code that sets the values for each cell. (Setting text and os on.) In fact, in that same code set onClickListener for each cell button:
v.nameTV.setText( "User Name" );
v.inviteIV.setOnClickListener( ourBoss ); // like this
the problem is what to set the listener to. In fact you want it to be your dialog fragment. "ourBoss" will be the DialogFragment. So (2) when the dialog fragment creates the adapter, pass it in:
in the dialog fragment creating the adaptor:
fosAdapter = new YourHappyAdapter(
getActivity(), getActivity().getLayoutInflater(),
otherStuff, otherStuff, this);
and in the adapter itself ...
public class YourHappyAdapter extends BaseAdapter
{
YourDialogFragmentClass ourBoss;
public FosAdapter(
Context context, LayoutInflater inflater,
blah, blah,
YourDialogFragmentClass ydfc)
{
blah
blah
ourBoss = ydfc;
}
Finally then (3) in the ordinary way, in YourDialogFragmentClass, you can have the usual onClick code!! Hooray, you're done!!
public void onClick(View v)
{
switch (v.getId())
{
case R.id.submit_button: // from the overall fragment screen
_searchNow();
break;
case R.id.cell_button: // that one's from a cell.
Utils.Log("IT WORKED !!!!!!!!!!!!!!!!! !!");
userWantsANewTank(v);
break;
default:
break;
}
}
It's (essentially) just not realistic to use the "old-fashioned" xml-handy-onClick method, when doing custom tables and custom dialog fragments!
Hope it helps someone!
So I've been looking around for android tutorials, help questions, etc.. I keep running into questions or tutorials hard for me to understand.
Here's my questions:
When I create an item in the visual designer, piece of code will be created in the .xml.
How can I get the ID of that item to use it in the .java file later?
How can I add callbacks when let's say a button gets clicked?
Here's what I have so far:
.java
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.Button;
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
public void Button_click_callback() // Where to add the callback in the .xml?
{
// How to get button ID and change the text of it?
//Knowing this will help me A LOT!
}
}
.xml
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="79dp"
android:layout_marginTop="32dp"
android:text="Button" />
When I create an item in the visual designer, piece of code will be created in the .xml. How can I get the ID of that item to use it in the .java file later?
Step #1: Ensure that you have assigned an ID for the widget in the designer (in your XML above, you will see this as android:id="#+id/button1)
Step #2: In Java, you can get at the Java object for that widget by calling findViewById(R.id.button1) at some appropriate time (e.g., from an Activity, sometime after you call setContentView()).
How can I add callbacks when let's say a button gets clicked?
Generally, there is a setter method for this, such as setOnClickListener() that you can call on the Button you retrieved by findViewById().
In the specific case of click events on widgets hosted by activities, there is also an android:onClick attribute you can have in the XML, which supplies the name of a method on your Activity that will get called when the widget is clicked, instead of your having to use the setter.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button1 = (Button)findViewById(R.id.button1);
button1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Do something in response to button click
}
});
}
All of this is extensively documented on the Android Developer site. You should be looking their for this basic stuff.
http://developer.android.com/guide/topics/ui/controls/button.html
You can use findViewById to get view ids from XML in Java, Make sure that you should declare the ids in views, otherwise it might cause exception which results apps force close
If you want call back with xml rather than programatically
you can declare android:onClick attribute on that Views in layout XML
For example, in your case you need add android:onClick="Button_click_callback" in your
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="79dp"
android:layout_marginTop="32dp"
android:text="Button"
android:onClick="Button_click_callback"/>
then you can use Button_click_callback method for call back in your Activity
public void Button_click_callback()
{
}
if you want call back programatically with java,
first you have get the view with findViewById and then you can add click listener to that view
You need to use the onClickListener and override the onClick method.
btn.setOnClickListener.(new View.OnClickListener(){
#Override
public void onClick(View v) {
//TO DO
}
});
OnClickListener is an interface. And thats why you need to override the OnClick method.
//in oncreate method of activity
//take button id like that
Button button1 = (Button)findViewById(R.id.button1);
//then implement on click listener for performing action on button
button1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Do something in response to button click
}
});
}
//you can also implements onclicklistener in activity.its interface;
public class MainActivity extends Activity implements View.OnClickListener
//then generate method
public void onClick(View view) {
}
public class MainActivity extends Activity {
private Button button1;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button1 = findViewById(R.id.button1);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
public void Button_click_callback() {
button1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Do something in response to button click
Log.e("click", "-------------button click");
}
});
}
}
Those two code snippets are equal, just implemented in two different ways.
Code Implementation
Button btn = (Button) findViewById(R.id.mybutton);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
myFancyMethod(v);
}
});
// some more code
public void myFancyMethod(View v) {
// does something very interesting
}
Above is a code implementation of an OnClickListener. And this is the XML implementation.
XML Implementation
<?xml version="1.0" encoding="utf-8"?>
<!-- layout elements -->
<Button android:id="#+id/mybutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Click me!"
android:onClick="myFancyMethod" />
1) First Look at your XML file.In code it shows
android:id="#+id/button1.
You can edit it on your own name.Same thing you can do to change it though the GUI appear at right side of your design.
You can get your ID using findViewById(R.id.your id name); function.
For an Example:
My button id is btn1.In my code I can use that button by getting it's Id as follows:
Button btn1=findViewById(R.id.btn1);
2)You can callback after creating your Button which you have created Before as follows;
btn1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Create your code
}
});
}
For the call backs - The android component needs to be registered in the calling device . The id of the components has to be unique in the xmls.
Using the unique id the components can be dynamically altered or the call backs can be used.
I have an activity with a spinner, and I was wondering if it is possible to close the spinner programmatically, if the user has opened it.
The whole story is that in the background I am running a process on a separate thread. When the process has finished, I invoke a Handler on the main activity and, depending on the outcome, I perform some tasks. It is then that I want to close the spinner, it the user has opened it.
The spinner is in the main.xml layout:
<Spinner android:id="#+id/birthPlaceSpinner" android:layout_weight="1"
android:layout_height="wrap_content" android:prompt="#string/select"
android:layout_width="fill_parent" />
and this is the Handler:
private class BirthplaceChangedHandler extends Handler {
#Override
public void handleMessage(Message msg) {
String placeFilterStr = birthPlaceFilterText.getText().toString();
if ("".equals(placeFilterStr) || placeFilterStr == null || validNewAddresses.isEmpty()) {
birthPlaceSpinner.setEnabled(false);
hideGeoLocationInformation();
} else {
birthPlaceSpinner.setEnabled(true);
}
adapter = new ArrayAdapter<String>(getApplicationContext(), R.layout.multiline_spinner_dropdown_item, validNewAddressesStr)
birthPlaceSpinner.setAdapter(adapter);
}
}
Cheers!
public static void hideSpinnerDropDown(Spinner spinner) {
try {
Method method = Spinner.class.getDeclaredMethod("onDetachedFromWindow");
method.setAccessible(true);
method.invoke(spinner);
} catch (Exception e) {
e.printStackTrace();
}
}
This works for me:
class SomeAdapter extends BaseAdapter implements SpinnerAdapter {
//......
public View getDropDownView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (view == null) {
//......
}
view.setOnClickListener(new ItemOnClickListener(parent));
return view;
}
//.....
}
and the click listener:
class ItemOnClickListener implements View.OnClickListener {
private View _parent;
public ItemOnClickListener(ViewGroup parent) {
_parent = parent;
}
#Override
public void onClick(View view) {
//.......
// close the dropdown
View root = _parent.getRootView();
root.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK));
root.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK));
}
}
Well its a little complicated than I thought.
I am adding the step by step details here. Try to follow it. I was able to achieve this in api level 10.
And this solution assumes that you are supposed to close the prompt dialog programatically when the user clicks on Home Button or If you had to move to next activity without user interaction
The first step is to create a Custom Spinner by extending Spinner Class.
Let's say, I have created a class called CustomSpinner in the package com.bts.sampleapp
My CustomSpinner class looks like this,
package com.bts.sampleapp;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.Spinner;
public class CustomSpinner extends Spinner{
Context context=null;
public CustomSpinner(Context context) {
super(context);
this.context=context;
}
public CustomSpinner(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public CustomSpinner(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
}
}
Now in your Xml file, replace Spinner element by this custom spinner,
<com.bts.sampleapp.CustomSpinner
android:id="#+id/spin"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
The next step is to initialize and set adapter to this spinner in your Activity class,
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
CustomSpinner spin=null;
spin=(CustomSpinner)findViewById(R.id.spin);
spin.setAdapter(spinnerAdapter); //you can set your adapter here.
}
The final step is to close the dialog when the user clicks on HomeButton or When the Activity moves to background. To do this, we override the onPause() like this,
#Override
protected void onPause() {
Log.i("Life Cycle", "onPause");
spin.onDetachedFromWindow();
super.onPause();
}
Now within the onPause() call the method spin.onDetachedFromWindow(); which does the job of closing the prompt dialog for you.
Now that being said, calling spin.onDetachedFromWindow(); from anywhere in your Activity should help you to close the spinner programatically. So if this is what you want, then remove the onpause().
I don't see a way to accomplish that -- there is no method on Spinner to close it. The "open" part of a Spinner is an AlertDialog on Android 1.x and 2.x, and I'm not completely sure how it is implemented on Honeycomb when using the holographic theme.
The only workaround would be to clone the source for Spinner and add in some code yourself to dismiss the dialog. But, again, it would not work on Honeycomb or higher until you can see and clone that code as well.
Beyond that, I would think that what you want is poor UX. If the user opened the Spinner, they are most likely actively examining the Spinner's contents and making a selection. Yanking that out from under their finger will confuse them, at best. Please consider an alternative approach.
Also, don't use getApplicationContext() unless you know why you are using getApplicationContext(). You do not need or even want getApplicationContext() when creating an ArrayAdapter.
I think you should scrap your use of Spinner and instead use an ImageView with a Frame Animation (i.e. <animation-list>) to create your own spinner. You just set the ImageView's background to be your Frame Animation drawable.
Then you can easily do something like this to start and stop it.
You would like to close your spinners from anywhere. Key injection for BACK pressed is the good solution but, here you are closing all the views at once.
How about setPressed(false)?
Link:
Close Spinners dropdown when two among all in a groupview are clicked simultaneously
Otherwise:
Try to make the Spinner focusable and focusableInTouchMode, and use clearFocus()
on it. Try to focus on the view below it using requestFocus() method.
Check if the spinner drop-down closes
Use the clearFocus() to close the spinner programitically
spinner.clearFocus();
Add clearfocus() in code.
Spinner spinner = (Spinner) findViewById(R.id.spinner);
spinner.clearFocus();
Use transparent background in xml
android:background="#android:color/transparent
<Spinner
android:id="#+id/spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#android:color/transparent"
android:clickable="false"
android:focusable="?android:attr/windowOverscan"
android:focusableInTouchMode="false"
android:pointerIcon="arrow"
android:spinnerMode="dialog"
android:theme="#style/ThemeOverlay.AppCompat.Light" />
Koltin Reflection
fun AppCompatSpinner.dismiss() {
val popup = AppCompatSpinner::class.java.getDeclaredField("mPopup")
popup.isAccessible = true
val listPopupWindow = popup.get(this) as ListPopupWindow
listPopupWindow.dismiss()
}