Android Spinner Make Item Clickable but not Selectable - android

Is it possible to have an item in my spinner which is clickable but not selectable?
The scenario here is that i have a Category spinner and i want the user to input his category himself. So i want the "add Item" selection to appear at the end of the Spinner's list and make it clickable only. Can someone help ?

You can do one thing, in listener if you got last position by default select 0 position and do you click action whatever you want.

yourSpinner?.onItemSelectedListener = object : AdapterView.OnItemSelectedListener{
override fun onNothingSelected(parent: AdapterView<*>?) {
}
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
// if position == n, open dialog here
// and then
yourSpinner?.setSelectablePosition(0);
}
}

you can do like
txtTimeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if(position == last){
txtTimeSpinner.setSelection(0);
}else {
//your code here for selection
}
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
and array first position is as default like ("Select Time")

Related

recyclerview-selection: stop auto item deselection when touching to the blank space inside the recyclerview

I am trying to use the recyclerview-selection library in my project. I followed this tutorial:
https://proandroiddev.com/a-guide-to-recyclerview-selection-3ed9f2381504
Everything workes fine. But I have a problem. If I tap/touch any blank space inside the RecyclerView, all the selected elements got deselected! I don't find any method or solution to disable this. What should I do?
I am using implementation 'androidx.recyclerview:recyclerview-selection:1.1.0-rc01' in my project.
Edit 1:
I set the RecyclerView background red to describe my problem. Here, blue items are selected items. If I click any red area, then all the selected items got unselected! The select and deselect should only be done by clicking the items. So, I need to disable this feature (or bug!), that unselect all items!
Example project: https://github.com/ImaginativeShohag/multiselection
Solution is to have an out of context selection item like:
class ItemLookup(private val recyclerView: RecyclerView) : ItemDetailsLookup<Long>() {
private val outOfContextSelection = object : ItemDetails<Long>() {
override fun getPosition(): Int = OUT_OF_CONTEXT_POSITION.toInt()
override fun getSelectionKey() = OUT_OF_CONTEXT_POSITION
}
override fun getItemDetails(e: MotionEvent): ItemDetails<Long>? {
recyclerView.findChildViewUnder(e.x, e.y)?.let {
return (recyclerView.getChildViewHolder(it) as?
SelectorBarAdapter.SelectorBarViewHolder)?.itemDetails
}
return outOfContextSelection
}
companion object {
const val OUT_OF_CONTEXT_POSITION = 10000L
}
}
so that when a view which is not one of our clickable elements is clicked we can identify further on a predicate like follows:
class SingleSelectionPredicate : SelectionTracker.SelectionPredicate<Long>() {
override fun canSetStateForKey(key: Long, nextState: Boolean): Boolean {
// warranties that an item can't be unselected on click
// warranties that clicks out of the item's scope are disabled
return nextState && key != ItemLookup.OUT_OF_CONTEXT_POSITION
}
override fun canSetStateAtPosition(position: Int, nextState: Boolean) = true
override fun canSelectMultiple() = false
}
You create your own SelectionTracker.SelectionPredicate<Long>.
Override the method canSetStateForKey(key: Long, nextState: Boolean)
like this:
override fun canSetStateForKey(#NonNull key: Long, nextState: Boolean): Boolean {
rv.findViewHolderForItemId(key)?.let { holder -> adapter.canSetStateForItem(holder as YourItemHolder<YourItem>, nextState)}
return true
}
and in your ViewHolder check if the item is already selected if so return false or vice versa.
Edit:
You can also define a "Selection Hotspot" by inSelectionHotspot(e: MotionEvent) in your ItemDetailsLookup.ItemDetails.
In your ViewHolder you can then check if the TouchEvent is in an area that requires a select or unselect.
for example:
override fun inSelectionHotspot(e: MotionEvent): Boolean {
val rect = Rect()
itemView.getGlobalVisibleRect(rect)
if (rect.contains(e.rawX.toInt(), e.rawY.toInt())) {
// in select region
} else {
// not in select region
}
}

How to make android spinner show same item always instead of changing

Long story short. I want my spinner to always show same first item "Add". When item selected from the list it should be gone from the list and the specific action happen. The text "Add" should still appear on spinner. So my question is how to make that spinner always show first item on his dataList? PS. I made that first item in the list don't show when drop down is open.
My layout:
<Spinner
android:id="#+id/spinner_add"
style="#style/Widget.AppCompat.Spinner.Underlined"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:backgroundTint="#color/colorButton" />
Method to set spinner adapter with data list:
private fun fillAddSpinner() {
val spinner: Spinner = findViewById(R.id.spinner_add)
val titles: MutableList<String> = ArrayList()
titles.add(resources.getString(R.string.add_advanced_filter))
for (filter in tableAdvancedFilters) {
titles.add(filter.title)
}
val dataAdapter = object : ArrayAdapter<String?>(this, R.layout.spinner_item,
titles as List<String?>
) {
override fun getDropDownView(
position: Int,
convertView: View?,
parent: ViewGroup
): View {
var v: View? = null
// If this is the initial dummy entry, make it hidden
if (position == 0) {
val tv = TextView(context)
tv.height = 0
tv.visibility = View.GONE
v = tv
} else { // Pass convertView as null to prevent reuse of special case views
v = super.getDropDownView(position, null, parent)
}
// Hide scroll bar because it appears sometimes unnecessarily, this does not prevent scrolling
parent.isVerticalScrollBarEnabled = false
return v!!
}
}
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
spinner.adapter = dataAdapter
}
I want it stay the same like it is now:
After user selects one item from spinner I will render specific filter choices.
If you want to programmatically set spinner selected item use the following: spinnerObject.setSelection(INDEX_OF_ITEM)

How to add a Hint in spinner

XML code of spinner:
<Spinner
android:id="#+id/mySpinner"
https://stackoverflow.com/questions
style="#style/Widget.AppCompat.DropDownItem.Spinner"
android:layout_width="match_parent"
android:layout_height="70dp" />`
.kotlin:
val myStrings = arrayOf("One", "Two" , "Three", "Four")
mySpinner.adapter = ArrayAdapter(this, android.R.layout.simple_spinner_dropdown_item, myStrings)
mySpinner.onItemSelectedListener = object :
AdapterView.OnItemSelectedListener {
override fun onNothingSelected(parent: AdapterView<*>?) {
TODO("not implemented")
//To change body of created functions use File | Settings | File Templates.
}
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
TODO("not implemented")
//To change body of created functions use File | Settings | File Templates.
}
}}
Equal to the "hint" option in Edittext, I need a default text in a Spinner.
There is not any default way to display hint in spinner.
For this you need to add one item manually in the array like below.
val myStrings = arrayOf("Select","One", "Two" , "Three", "Four")
Now,
Define custom Adapter for the Spinner and disable the first item like below.
#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;
}
}
You can change the color like below
#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;
}
For more info please visit:-
Add hint in spinner

Spinner - show hint when adapter is empty

I know there have been several questions that dealt with the problem how to add the "Select one..." hint for the Spinner before the first selection is made. But that's not my case.
What I need is to display the hint only when the SpinnerAdapter is empty. By default in such case, nothing happens on click (but that is not the major problem), and most of all, the spinner doesn't display any text, so it looks like this, which obviously doesn't feel right:
Any idea how to simply handle this problem? I've come up with 2 possible solutions, but I don't like any of them very much:
If the SpinnerAdapter is empty, hide the Spinner from the layout and display a TextView with the same background as the Spinner instead.
Implement a custom SpinnerAdapter whose getCount() returns 1 instead of 0 if the internal list is empty, and at the same time, have its getView() return a TextView with the required "Empty" message, possibly grey-coloured. But that would require specific checking if the selected item is not the "Empty" one.
You can use this SpinnerWithHintAdapter class below
class SpinnerWithHintAdapter(context: Context, resource: Int = android.R.layout.simple_spinner_dropdown_item) :
ArrayAdapter<Any>(context, resource) {
override fun isEnabled(position: Int): Boolean {
return position != 0
}
override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View {
return (super.getDropDownView(position, convertView, parent) as TextView).apply {
if (position == 0) {
// Set the hint text color gray
setTextColor(Color.GRAY)
} else {
setTextColor(Color.BLACK)
}
}
}
fun attachTo(spinner: Spinner, itemSelectedCallback: ((Any?) -> Unit)? = null) {
spinner.apply {
adapter = this#SpinnerWithHintAdapter
itemSelectedCallback?.let {
onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onNothingSelected(parent: AdapterView<*>?) {}
override fun onItemSelected(
parent: AdapterView<*>?,
view: View?,
position: Int,
id: Long
) {
val selectedItem = parent?.getItemAtPosition(position)
// If user change the default selection
// First item is disable and it is used for hint
if (position > 0) {
it(selectedItem)
}
}
}
}
}
}
}
How to use? Let's assume I have data class called City
data class City(
val id: Int,
val cityName: String,
val provinceId: Int
) {
/**
* By overriding toString function, you will show the dropdown text correctly
*/
override fun toString(): String {
return cityName
}
}
In the activity, initiate the adapter, add hint(first item), add main items, and finally attach it to your spinner.
SpinnerWithHintAdapter(this#MyActivity)
.apply {
// add hint
add("City")
// add your main items
for (city in cityList) add(city)
// attach this adapter to your spinner
attachTo(yourSpinner) { selectedItem -> // optional item selected listener
selectedItem?.apply {
if (selectedItem is City) {
// do what you want with the selected item
}
}
}
}

Multiple spinners and onItemSelected

I have two spinners that trigger the onItemSelected event. The question is How can I know which one triggered such event ? So far I tried:
public void onItemSelected(AdapterView<?> parent, View view, int position, long id)
{
Log.d("form","onitemselected");
switch (view.getId()) {
case R.id.region_spinner:
Region r = (Region)sregions.getSelectedItem();
Log.d("form","regionid:" + r.id);
break;
case R.id.state_spinner:
Log.d("form","state id:");
break;
}
But only the first Log is displayed, so there's no match in the switch.
use:
switch(parent.getId()) {
...
}
instead is what you need.
The view in your parameter is the actual 'row' (i.e. the clicked child of spinner item), and the parent is the actual 'spinner' that you are after.
Use below code if you have multiple spinners in one activity and you are using onItemSelected override method
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
if (parent!!.id == R.id.spinner_1) {
// first spinner selected
} else if (parent!!.id == R.id.spinner_2) {
// second spinner selected
}
}
either you can use switch case
Spinner is a subclass of AdapterView. The parent object passed into the method is the spinner in which the item was selected.
At first in onCreate :
Spinner cit_for_bus, bus_number;
cit_for_bus = (Spinner) findViewById(R.id.cit_for_bus);
bus_number = (Spinner) findViewById(R.id.bus_number);
cit_for_bus.setOnItemSelectedListener(this);
bus_number.setOnItemSelectedListener(this);
don't forget to use :
you have to bind/tie spinners to onItemSelected
cit_for_bus.setOnItemSelectedListener(this);
bus_number.setOnItemSelectedListener(this);
and use implement for class :
public class MainActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener
outSide of onCreate use this :
#Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
if (adapterView.getId() == R.id.cit_for_bus) {
Toast.makeText(getApplicationContext(), adapterView.getId() + "/ " + adapterView.getCount() + "/" + adapterView.getSelectedItem(), Toast.LENGTH_LONG).show();
} else if (adapterView.getId() == R.id.bus_number) {
Toast.makeText(getApplicationContext(), adapterView.getId() + "/ " + adapterView.getCount() + "/" + adapterView.getSelectedItem(), Toast.LENGTH_LONG).show();
}
}
If you import your XML on Kotlin you can use it as so:
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id:
Long) {
when (parent)
firstSpinner -> {
// first spinner selection
}
secondSpinner -> {
// second spinner selected
}
}
}

Categories

Resources