I have a cutsom ListView and custom ArrayAdapter. My ListView contains TextView and CheckBox. I want to implement onClick() method on CheckBox.
custom_ListView.xml
<TextView
android:id="#+id/text_inList"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginStart="20dp" />
<com.google.android.material.checkbox.MaterialCheckBox
android:id="#+id/checkbox_inList"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:focusable="false"/>
CustomAdapter.java
public class CustomAdapter extends ArrayAdapter<Task> {
private List<Task> tasks;
private Activity context;
private DataBase dataBase;
private Task task;
// Constructor
public CustomAdapter(Activity context, List<Task> tasks){
super(context,R.layout.list_with_checkbox,tasks);
this.context=context;
this.tasks=tasks;
}
#Override
public View getView(final int postion, View view, ViewGroup parent){
view = context.getLayoutInflater().inflate(R.layout.list_with_checkbox, null, true);
CheckBox checkBox=(CheckBox)view.findViewById(R.id.checkbox_inList);
checkBox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//position should be equal to the position of CheckBox that is clicked
Toast.makeText(context,String.valueOf(postion),Toast.LENGTH_SHORT).show();
}
});
return view;
}
And problem is that when I run this app, I've found that when I click any of the CheckBoxes of ListView, Toast message shows only the last position of the list. In other words , I can't get position of CheckBox that is clicked in ListView. Also I've tried to implement onItemClickListener() in MainActivity , but it did not react on CheckBox click instead it reacted on TextView click.
I am trying to add a Hint in the spinner widget as there is no option of Hint as in EditText, I want to show Gender as a Hint and when clicked it must show only Male and Female not the hint.
How it can be Done Only Using XML
XML code of spinner.
<Spinner
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/spinner1"
android:entries="#array/gender"
android:layout_marginTop="10dp"
android:layout_marginLeft="25dp"
android:layout_marginRight="25dp"
android:layout_gravity="center_horizontal" />
String Array of the spinner
<string-array name="gender">
<item>Male</item>
<item>Female</item>
</string-array>
In the adapter you can set the first item as disabled. Below is the sample code
#Override
public boolean isEnabled(int position) {
if (position == 0) {
// Disable the first item from Spinner
// First item will be use for hint
return false;
} else {
return true;
}
}
And set the first item to grey color.
#Override
public View getDropDownView(int position, View convertView,
ViewGroup parent) {
View view = super.getDropDownView(position, convertView, parent);
TextView tv = (TextView) view;
if (position == 0) {
// Set the hint text color gray
tv.setTextColor(Color.GRAY);
} else {
tv.setTextColor(Color.BLACK);
}
return view;
}
And if the user selects the first item then do nothing.
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
String selectedItemText = (String) parent.getItemAtPosition(position);
// If user change the default selection
// First item is disable and it is used for hint
if (position > 0) {
// Notify the selected item text
Toast.makeText(getApplicationContext(), "Selected : " + selectedItemText, Toast.LENGTH_SHORT).show();
}
}
Refer the below link for detail.
How to add a hint to Spinner in Android
For Kotlin
What will you get:
Gray color if the hint is selected
Drop down list with gray color of the hint
Black color if something else than the hint is selected
I have added 5. step what changes the color of the text in the spinner depending on the selected item, because I couldn't find it here. In this case it is needed to change the text color to gray when the first item is selected in order to it looks like a hint.
Define a spinner in your activity_layout.xml
<Spinner
android:id="#+id/mySpinner"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
Define the string array in string.xml where the first item will be a hint.
<string-array name="your_string_array">
<item>Hint...</item>
<item>Item1</item>
<item>Item2</item>
<item>Item3</item>
</string-array>
Set up the spinner in the onCreate method in your Activity.kt
Get string array from resources
val items= resources.getStringArray(R.array.your_string_array)
Create spinner adapter
val spinnerAdapter= object : ArrayAdapter<String>(this,android.R.layout.simple_spinner_item, items) {
override fun isEnabled(position: Int): Boolean {
// Disable the first item from Spinner
// First item will be used for hint
return position != 0
}
override fun getDropDownView(
position: Int,
convertView: View?,
parent: ViewGroup
): View {
val view: TextView = super.getDropDownView(position, convertView, parent) as TextView
//set the color of first item in the drop down list to gray
if(position == 0) {
view.setTextColor(Color.GRAY)
} else {
//here it is possible to define color for other items by
//view.setTextColor(Color.RED)
}
return view
}
}
Set drop down view resource and attach the adapter to your spinner.
spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
mySpinner.adapter = spinnerAdapter
Change the color of the text in the spinner depending on the selected item
mySpinner.onItemSelectedListener = object: AdapterView.OnItemSelectedListener{
override fun onNothingSelected(parent: AdapterView<*>?) {
}
override fun onItemSelected(
parent: AdapterView<*>?,
view: View?,
position: Int,
id: Long
) {
val value = parent!!.getItemAtPosition(position).toString()
if(value == items[0]){
(view as TextView).setTextColor(Color.GRAY)
}
}
}
There are two ways you can use spinner:
static way
android:spinnerMode="dialog"
and then set:
android:prompt="#string/hint_resource"
dynamic way
spinner.setPrompt("Gender");
Note: It will work like a Hint but not actually it is.
May it help!
Step 1:
Your array looks like. last item your hint
Ex : private String[] yourArray = new String[] {"Staff", "Student","Your Hint"};
Step 2:
Create HintAdpater.java (Just copy & paste)
This class not return last item.. So your Hint not displays.
HintAdapter.java
package ajax.com.vvcoe.utils;
import android.content.Context;
import android.widget.ArrayAdapter;
import java.util.List;
public class HintAdapter extends ArrayAdapter<String> {
public HintAdapter(Context context, int resource) {
super(context, resource);
}
public HintAdapter(Context context, int resource, int textViewResourceId) {
super(context, resource, textViewResourceId);
}
public HintAdapter(Context context, int resource, String[] objects) {
super(context, resource, objects);
}
public HintAdapter(Context context, int resource, int textViewResourceId, String[] objects) {
super(context, resource, textViewResourceId, objects);
}
public HintAdapter(Context context, int resource, List<String> objects) {
super(context, resource, objects);
}
public HintAdapter(Context context, int resource, int textViewResourceId, List<String> objects) {
super(context, resource, textViewResourceId, objects);
}
#Override
public int getCount() {
// don't display last item. It is used as hint.
int count = super.getCount();
return count > 0 ? count - 1 : count;
}
}
Step 3:
Set spinner adapter like this
HintAdapter hintAdapter=new HintAdapter(this,android.R.layout.simple_list_item_1,yourArray);
yourSpinner.setAdapter(hintAdapter);
// show hint
yourSpinner.setSelection(hintAdapter.getCount());
Credit goes to #Yakiv Mospan
from this answer - https://stackoverflow.com/a/22774285/3879847
I modify some changes only..
This can be done in a very simple way. Instead of setting the adapter using the built-in values (android.R.layout.simple_list_item_1), create your own xml layout for both TextView and DropDown, and use them. In the TextView layout, define Hint text and Hint color. Last step, create and empty item as the first item in the item array defined in Strings.
<string-array name="professional_qualification_array">
<item></item>
<item>B.Pharm</item>
<item>M.Pharm</item>
<item>PharmD</item>
</string-array>
Create XML layout for Spinner TextView (spnr_qualification.xml)
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="20sp"
android:hint="Qualification"
android:textColorHint="#color/light_gray"
android:textColor="#color/blue_black" />
Create XML layout for spinner DropDown.(drpdn_qual.xml)
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#android:id/text1"
style="?android:attr/spinnerDropDownItemStyle"
android:maxLines="1"
android:layout_width="match_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:ellipsize="marquee"
android:textColor="#FFFFFF"/>
Define spinner in the main XML layout
<Spinner
android:id="#+id/spnQualification"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginTop="10dp"
android:paddingLeft="10dp"
android:paddingBottom="5dp"
android:paddingTop="5dp"
/>
And finally in the code, while setting adapter for the spinner, use your custom XML layout.
ArrayAdapter<CharSequence> qual_adapter = ArrayAdapter.createFromResource(this, R.array.professional_qualification_array,R.layout.spnr_qualification);
qual_adapter.setDropDownViewResource(R.layout.drpdn_qual);
spnQualification.setAdapter(qual_adapter)
make your hint at final position in your string array like this
City is the hint here
array_city = new String[]{"Irbed", "Amman", "City"};
and then in your array adapter
ArrayAdapter<String> adapter_city = new ArrayAdapter<String>(getContext(), android.R.layout.simple_spinner_item, array_city) {
#Override
public int getCount() {
// to show hint "Select Gender" and don't able to select
return array_city.length-1;
}
};
so the adapter return just first two item
and finally in onCreate() method or what ,,, make Spinner select the hint
yourSpinner.setSelection(array_city.length - 1);
For Kotlin !!
Custom Array adapter to hide the last item of the spinner
import android.content.Context
import android.widget.ArrayAdapter
import android.widget.Spinner
class HintAdapter<T>(context: Context, resource: Int, objects: Array<T>) :
ArrayAdapter<T>(context, resource, objects) {
override fun getCount(): Int {
val count = super.getCount()
// The last item will be the hint.
return if (count > 0) count - 1 else count
}
}
Spinner Extension function to set hint on spinner
fun Spinner.addHintWithArray(context: Context, stringArrayResId: Int) {
val hintAdapter =
HintAdapter<String>(
context,
android.R.layout.simple_spinner_dropdown_item,
context.resources.getStringArray(stringArrayResId)
)
hintAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
adapter = hintAdapter
setSelection(hintAdapter.count)
}
How to use: add the extension by passing context and array on Spinner
spinnerMonth.addHintWithArray(context, R.array.months)
Note: The hint should be the last item of your string array
<string-array name="months">
<item>Jan</item>
<item>Feb</item>
<item>Mar</item>
<item>Apr</item>
<item>May</item>
<item>Months</item>
</string-array>
The simplest way I found was this:
Creates a TextView or LinearLayout and places it along with the Spinner in a RelativeLayout. Initially the textview will have the text as if it were the hint "Select one ...", after the first click this TextView is invisible, disabled and calls the Spinner that is right behind it.
Step 1:
In the activity.xml that finds the spinner put:
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Spinner
android:id="#+id/sp_main"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:spinnerMode="dropdown" />
<LinearLayout
android:id="#+id/ll_hint_spinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="center">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="Select..."/>
</LinearLayout>
</RelativeLayout>
Step 2:
In your Activity.java type:
public class MainActivity extends AppCompatActivity {
private LinearLayout ll_hint_spinner;
private Spinner sp_main;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ll_hint_spinner = findViewById(R.id.ll_hint_spinner);
sp_main = findViewById(R.id.sp_main);
//Action after clicking LinearLayout / Spinner;
ll_hint_spinner.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//By clicking "Select ..." the Spinner is requested;
sp_main.performClick();
//Make LinearLayout invisible
setLinearVisibility(false);
//Disable LinearLayout
ll_hint_spinner.setEnabled(false);
//After LinearLayout is off, Spinner will function normally;
sp_main.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
sp_main.setSelection(position);
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
setLinearVisibility(true);
}
});
}
});
}
//Method to make LinearLayout invisible or visible;
public void setLinearVisibility(boolean visible) {
if (visible) {
ll_hint_spinner.setVisibility(View.VISIBLE);
} else {
ll_hint_spinner.setVisibility(View.INVISIBLE);
}
}
}
Example1 SameExample2 SameExample3
The examples of the images I used a custom Spinner, but the result of the last example will be the same.
Note: I have the example in github: click here!
The trick is this line
((TextView) view).setTextColor(ContextCompat.getColor(mContext, R.color.login_input_hint_color));
use it in the onItemSelected. Here is my code with more context
List<String> list = getLabels(); // First item will be the placeholder
ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(mContext, android.R.layout.simple_spinner_item, list);
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(dataAdapter);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
// First item will be gray
if (position == 0) {
((TextView) view).setTextColor(ContextCompat.getColor(mContext, R.color.login_input_hint_color));
} else {
((TextView) view).setTextColor(ContextCompat.getColor(mContext, R.color.primary_text));
}
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
What worked for me is you would set your spinner up with a list of items including the hint at the beginning.
final MaterialSpinner spinner = (MaterialSpinner) findViewById(R.id.spinner);
spinner.setItems("Select something in this list", getString(R.string.ABC), getString(R.string.ERD), getString(R.string.KGD), getString(R.string.DFK), getString(R.string.TOE));
Now when the user actually selects something in the list, you would use the spinner.setItems method to set the list to everything besides your hint:
spinner.setOnItemSelectedListener(new MaterialSpinner.OnItemSelectedListener<String>() {
#Override public void onItemSelected(MaterialSpinner view, int position, long id, String item) {
spinner.setItems(getString(R.string.ABC), getString(R.string.ERD), getString(R.string.KGD), getString(R.string.DFK), getString(R.string.TOE));
}
The hint will be removed as soon as the user selects something in the list.
I've managed to add a 'hint' that is omitted from the drop down list. If my code looks a bit weird it's because I'm using Xamarin.Android so it's in C# but for all intents (heh) and purposes the Java equivalent should have the same effect.
The gist is that I've created a custom ArrayAdapter that will detect if it is the hint in the GetDropDownView method. If so then it will inflate an empty XML to hide the hint from the drop down.
My spinnerItem.xml is ...
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/spinnerText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="#dimen/text_left_padding"
android:textAppearance="?android:attr/textAppearanceLarge"/>
My 'empty' hintSpinnerDropdownItem.xml which will hide the hint.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
I pass in an array of CustomObj without the hint. That's why I have the additional AddPrompt method to insert the hint at the beginning before it's passed to the parent constructor.
public class CustomArrayAdapter: ArrayAdapter<CustomObj>
{
private const int HintPosition = 0;
private const CustomObj HintValue = null;
private const string Hint = "Hint";
public CustomArrayAdapter(Context context, int textViewResourceId, CustomObj[] customObjs) : base(context, textViewResourceId, AddPrompt(customObjs))
{
private static CustomObj[] AddPrompt(CustomObj[] customObjs)
{
CustomObj[] customObjsWithHint = new CustomObj[customObjs.Length + 1];
CustomObj[] hintPlaceholder = { HintValue };
Array.Copy(hintPlaceholder , customObjsWithHint , 1);
Array.Copy(customObjs, 0, customObjsWithHint , 1, customObjs.Length);
return customObjsWithHint ;
}
public override Android.Views.View GetView(int position, Android.Views.View convertView, ViewGroup parent)
{
CustomObj customObj = GetItem(position);
bool isHint = customObj == HintValue;
if (convertView == null)
{
convertView = LayoutInflater.From(base.Context).Inflate(Resource.Layout.spinnerItem, parent, false);
}
TextView textView = convertView.FindViewById<TextView>(Resource.Id.spinnerText);
textView.Text = isHint ? Hint : customObj.Value;
textView.SetTextColor(isHint ? Color.Gray : Color.Black);
return convertView;
public override Android.Views.View GetDropDownView(int position, Android.Views.View convertView, ViewGroup parent)
{
CustomObj customObj = GetItem(position);
if (position == HintPosition)
{
convertView = LayoutInflater.From(base.Context).Inflate(Resource.Layout.hintSpinnerDropdownItem, parent, false);
}
else
{
convertView = LayoutInflater.From(base.Context).Inflate(Resource.Layout.spinnerItem, parent, false);
TextView textView = convertView.FindViewById<TextView>(Resource.Id.spinnerText);
textView.Text = customObj.Value;
}
return convertView;
}
}
It is very simple if position is '0' then call onNothingSelected method in OnItemSelectedListener. It worked fine for me.
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
**if (position == 0)
{
onNothingSelected(parent);
}**
else {
String mechanicType = mechanicTpes[position];
Toast.makeText(FirstUser.this, "Mechanic Tpye : "+mechanicType, Toast.LENGTH_SHORT).show();
}
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
Toast.makeText(FirstUser.this, "NOTHING SELECTED IN SPINNER", Toast.LENGTH_SHORT).show();
}
});
See the answer with lightweight and high customisable library
https://stackoverflow.com/a/73085435/6694920
You can set the spinner prompt:
spinner.setPrompt("Select gender...");
I've created a custom RelativeLayout view which I inflate with merge tags.
In this custom view I have a button which I want it to do something.
I've tried many things but the button simply refuses to be clicked.
The strange part is, I can find the views and change their visibility just fine.
Is it possible to click a button this way, or should it be done in a different way?
The things I've tried:
Anonymous innerclass for onClickListener
XML attribute for onClick
View onClick with onClickListener(this)
Check if it's clickable with code (it returns true)
Added clickable(true) to both XML and code.
Private context from constructor instead of getContext()
Moved logic from init() to onFinishInflate()
Used the view from inflater to find views
Switch from inflate() to LayoutInflater
Inflated custom view:
<?xml version="1.0" encoding="utf-8"?>
<merge
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/internet_view_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="#string/internet_offline"/>
<custom.IconView
android:id="#+id/internet_view_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="ICON"
android:visibility="invisible"
android:layout_below="#+id/internet_view_text"/>
<Button
android:id="#+id/internet_view_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="BUTTON"
android:clickable="true"
android:layout_below="#+id/internet_view_text"/>
</merge>
Relevant part of the parent view:
<custom.NoInternetView
android:id="#+id/webview_no_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible"
app:automaticReconnect="false"/>
The class file:
public class NoInternetView extends RelativeLayout implements View.OnClickListener {
private static final String TAG = NoInternetView.class.getSimpleName();
private static ConnectivityChangeListener listener;
private static boolean automaticReconnect;
private Context mContext;
private View view;
private Button button;
public NoInternetView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NoInternetView, defStyleAttr, 0);
automaticReconnect = a.getBoolean(R.styleable.NoInternetView_automaticReconnect, false);
a.recycle();
init();
}
public NoInternetView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public NoInternetView(Context context) {
this(context, null);
}
#Override
protected void onFinishInflate() {
Log.d(TAG, "onFinishInflate");
super.onFinishInflate();
button = (Button) view.findViewById(R.id.internet_view_button);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Log.d(TAG, "Clicked on some Button");
if (listener != null && NetworkHelper.hasAccess(getContext())) {
listener.connected();
}
}
});
button.setClickable(true);
boolean clicked = button.callOnClick();
Log.d(TAG, "clicked: "+clicked);
TextView text = (TextView) view.findViewById(R.id.internet_view_icon);
text.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Log.d(TAG, "Clicked on some TextView");
if (listener != null && NetworkHelper.hasAccess(getContext())) {
listener.connected();
}
}
});
//check if the attribute 'automaticReconnect' is set to true
//if so, show an icon instead of a button
if (automaticReconnect){
button.setVisibility(INVISIBLE);
view.findViewById(R.id.internet_view_icon).setVisibility(VISIBLE);
}
}
public void init(){
Log.d(TAG, "init");
view = LayoutInflater.from(mContext).inflate(R.layout.no_internet_view, this, false);
}
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
Log.d(TAG, "something happened?");
return super.dispatchKeyEvent(event);
}
#Override
public void onClick(View v) {
Log.d(TAG, "Clicked on Button(TextView)");
if (listener != null && NetworkHelper.hasAccess(getContext())){
listener.connected();
}
}
So I got it to work. Here are the things I did to make it work.
Replace the merge tag with RelativeLayout, because you are inflating the layout to show inside a view. More info here: Android xml merge layout error on inflate
You have set android:visibility="invisible", change that to android:visibility="visible" (This is just to get the view visible, you can later change it programatically)
Add the below line to the init() method of your NoInternetView. You are inflating the layout with all the views, but only when you add this view, you will be able to see it.
public void init(){
Log.d(TAG, "init");
view = LayoutInflater.from(mContext).inflate(R.layout.no_internet_view, this, false);
this.addView(view);}
Once you are done with this, the button will be visible and clicking on the button will be clickable. You can either use anonymous onClickListener or make the view implement the onClickListener and override the onClick() method. Anything works.
I have an Android Spinner and I want to listen the event when the user press "Back Key" when the spinner's select panel is showing.I have implement the OnItemSelectedListener ,but the onNothingSelected(AdapterView arg0) was not invoked when press back key.
I just want to listen the event when user select nothing( or the select panel disappear) .
Is there a correct way to do this?
Thanks!
Spinner s1 = (Spinner) findViewById(R.id.spinner1);
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
this, R.array.colors, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
s1.setAdapter(adapter);
s1.setOnItemSelectedListener(
new OnItemSelectedListener() {
public void onItemSelected(
AdapterView<?> parent, View view, int position, long id) {
showToast("Spinner1: position=" + position + " id=" + id);
}
public void onNothingSelected(AdapterView<?> parent) {
showToast("Spinner1: unselected");
}
});
This is a sample in Android 2.2 SDK,it's also not show "Spinner1: unselected" when the select panel disappear.
It looks like you won't be able to do what you want without extending the Spinner class. It seems that Spinner doesn't register an OnCancelListener with the AlertDialog it builds to display the items.
Code from Spinner.java:
#Override
public boolean performClick() {
boolean handled = super.performClick();
if (!handled) {
handled = true;
Context context = getContext();
final DropDownAdapter adapter = new DropDownAdapter(getAdapter());
AlertDialog.Builder builder = new AlertDialog.Builder(context);
if (mPrompt != null) {
builder.setTitle(mPrompt);
}
mPopup = builder.setSingleChoiceItems(adapter, getSelectedItemPosition(), this).show();
}
return handled;
}
public void onClick(DialogInterface dialog, int which) {
setSelection(which);
dialog.dismiss();
mPopup = null;
}
Also, setSelection is only called when an item in the dialog is clicked. This won't be called when the user presses the back button since that is an OnCancel event.
Extending Spinner will be a bit of a pain since you have to copy everything back to AdapterView into your source from the android source since various member fields necessary for implementation are only exposed at the package level.
Another approach is to create a minimal custom spinner dropdown item, ie:
<com.mypackage.MyTextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#android:id/text1"
style="?android:attr/spinnerDropDownItemStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="25dp"
/>
and then intercept onDetachedFromWindow():
public class MyTextView extends TextView {
public MyTextView(Context context) {
super(context);
}
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
// Callback here
}
}
You can finesse this if you use a custom ArrayAdapter to set only one of the dropdown items to do the callback, as well as setting
suitable context for the callback, etc.
Depending on what you do inside the callback, you may want to
post it as a runnable, so that the spinner is fully cleaned up
before it does anything.
I'm trying to bind data from my SQLiteDatabase to a ListView. I'm currently using a SimpleCursorAdapter to fill in my ListView. Unfortunately this doesn't seem to work with setting a CheckBox's checked attribute.
This is how I do it now; instead of changing the CheckBox's checked status the adapter is filling in the value to the text argument, so the value is displayed right of the CheckBox as text.
Java:
setListAdapter( new SimpleCursorAdapter( this,
R.layout.mylist,
data,
new String[] { Datenbank.DB_STATE, Datenbank.DB_NAME },
new int[] { R.id.list_checkbox, R.id.list_text }
) );
mylist.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:id="#+id/LinearLayout01"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
>
<CheckBox android:text=""
android:id="#+id/list_checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="false"
></CheckBox>
<TextView android:text=""
android:id="#+id/list_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
></TextView>
</LinearLayout>
Edit: The field in the database is of course of type boolean and I've also tried to assign an id to the checked field to fill the value in.
You could set a custom SimpleCursorAdapter.ViewBinder:
SimpleCursorAdapter cursorAdapter = new SimpleCursorAdapter(/* ur stuff */);
cursorAdapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
if(columnIndex == 1) {
CheckBox cb = (CheckBox) view;
cb.setChecked(cursor.getInt(1) > 0);
return true;
}
return false;
}
});
The setViewValue method is invoked for every column you specify in the SimpleCursorAdapter constructor and gives you a good place to manipulate some (or all) of the views.
I'm not sure how you would do this aside from creating a custom Adapter that overrode newView/bindView or getView, depending on what you override (ResourceCursorAdapter is a good one).
Ok, so here's an example. I didn't test to see if it would compile because I'm at work, but this should definitely point you in the right direction:
public class MyActivity extends ListActivity {
MyAdapter mListAdapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Cursor myCur = null;
myCur = do_stuff_here_to_obtain_a_cursor_of_query_results();
mListAdapter = new MyAdapter(MyActivity.this, myCur);
setListAdapter(mListAdapter);
}
private class MyAdapter extends ResourceCursorAdapter {
public MyAdapter(Context context, Cursor cur) {
super(context, R.layout.mylist, cur);
}
#Override
public View newView(Context context, Cursor cur, ViewGroup parent) {
LayoutInflater li = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
return li.inflate(R.layout.mylist, parent, false);
}
#Override
public void bindView(View view, Context context, Cursor cur) {
TextView tvListText = (TextView)view.findViewById(R.id.list_text);
CheckBox cbListCheck = (CheckBox)view.findViewById(R.id.list_checkbox);
tvListText.setText(cur.getString(cur.getColumnIndex(Datenbank.DB_NAME)));
cbListCheck.setChecked((cur.getInt(cur.getColumnIndex(Datenbank.DB_STATE))==0? false:true))));
}
}
}
You can solve that problem by creating a custom CheckBox widget like so:
package com.example.CustomCheckBox;
public class CustomCheckBox extends CheckBox {
public CustomCheckBox(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public CustomCheckBox(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomCheckBox(Context context) {
super(context);
}
protected void onTextChanged(CharSequence text, int start, int before, int after) {
if (text.toString().compareTo("") != 0) {
setChecked(text.toString().compareTo("1") == 0 ? true : false);
setText("");
}
}
}
The onTextChanged function will be called when the ListView binds the data to the CheckBox (ie. Adding either "0" or "1"). This will catch that change and add in your boolean processing. The 1st "if" statement is needed so as to not create infinite recursion.
Then provide your custom class in to the layout file as such:
<com.example.CustomCheckBox
android:id="#+id/rowCheckBox"
android:layout_height="fill_parent"
android:layout_width="wrap_content" />
That should do it!