Kotlin Spinner selection - android

I created a custom spinner adapter, populated with data, on runtime it drops the list, but nothing can be selected. The selection works with the stock ArrayAdapter, but the custom. Please help, what am I missig...
DetailsActivity.kt:
'''class DetailsActivity : AppCompatActivity() {
.
.
.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.word_details)
val spinner: Spinner = findViewById(R.id.topic_spinner)
spinner.adapter = cAdapter(applicationContext, fillSpinner())
val listener = object : AdapterView.OnItemSelectedListener{
override fun onItemSelected(parent: AdapterView<*>?, view: View, pos: Int, id: Long) {
Toast.makeText(applicationContext, "Selected: $pos", Toast.LENGTH_SHORT).show()
}
override fun onNothingSelected(parent: AdapterView<*>?) {
}
}
spinner.onItemSelectedListener = listener
.
.
.
'''
fillSpinner function:
'''
fun fillSpinner(): ArrayList{
val topics = ArrayList<String>()
topics.clear()
val h_cursor = dbHandler.get_h_AllRow()
h_cursor.moveToFirst()
while (!h_cursor.isAfterLast){
topics.add(h_cursor.getString(h_cursor.getColumnIndex(DBHelper.H_COLUMN_TOPIC)))
h_cursor.moveToNext()
}
return topics
}
'''
cAdapter class:
'''
class cAdapter(val ctx: Context, val items: ArrayList) :
ArrayAdapter(ctx, 0, items) {
override fun getView(position: Int, recycledView: View?, parent: ViewGroup): View {
return this.createView(position, recycledView, parent)
}
override fun getDropDownView(position: Int, recycledView: View?, parent: ViewGroup): View {
return this.createView(position, recycledView, parent)
}
private fun createView(position: Int, recycledView: View?, parent: ViewGroup): View {
val item = getItem(position)
val view = recycledView ?: LayoutInflater.from(context).inflate(
R.layout.spinner_layout,
parent,
false)
view.IB_cancel.setImageResource(android.R.drawable.ic_delete)
view.IB_cancel.setOnClickListener {
Toast.makeText(context, "DELETE SOMETHING!", Toast.LENGTH_SHORT).show()
}
view.t_sp_holder.text = item
return view
}
}
'''
As I see, the problem should lie somewhere here in theese lines. Please give some advice, I am new at Kotlin.

Related

I have to press two times an item for delete it using setOnClickListener when i have only one item in the list

I have this code...the idea is that when the user push imagedeletenumberlistview component the element that the user has pressed is deleted. If I have multiple items it works fine, but when I have one item I have to double press the item for it to delete me.
numberViewModel.numbers().observe(viewLifecycleOwner){ listN->
if (listN.isNotEmpty()){
val adapter=PhonesAdapter(requireContext(),listN)
binding.listPhones.adapter=adapter
binding.listPhones.setOnItemClickListener { _, view, position, _ ->
view.findViewById<ImageView>(R.id.imagedeletenumberlistview).setOnClickListener {
Toast.makeText(requireContext(),"Contact delete ${listN[position].contactName}",Toast.LENGTH_SHORT).show()
numberViewModel.deletenumber(listN[position])
}
}
}else{
val adapter=PhonesAdapter(requireContext(),listN)
binding.listPhones.adapter=adapter
}
}
UPDATE 1
PhonesAdapter class:
class PhonesAdapter (private var contex:Context, private val phones:List<NumberEntity>) : ArrayAdapter<NumberEntity> (contex,0,phones){
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
val v= LayoutInflater.from(context).inflate(R.layout.item_phones,parent,false)
val phones=phones[position]
v.findViewById<TextView>(R.id.contactName).text=phones.contactName
v.findViewById<TextView>(R.id.phoneNumber).text=phones.number
return v
}
}emphasized text
Firstly, you have to create an interface listener in your PhoneAdapter and set OnClickListener for imagedeletenumberlistview in getView method like this:
class PhonesAdapter(private var context: Context, private val phones: List<NumberEntity>) :
ArrayAdapter<NumberEntity>(contex, 0, phones) {
private lateinit var mListener: ItemClicker
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
val v = LayoutInflater.from(context).inflate(R.layout.item_phones, parent, false)
val phones = phones[position]
v.findViewById<TextView>(R.id.contactName).text = phones.contactName
v.findViewById<TextView>(R.id.phoneNumber).text = phones.number
v.findViewById<ImageView>(R.id.imagedeletenumberlistview).setOnClickListener {
mListener.onDeleteClick(position)
}
return v
}
interface ItemClicker {
fun onDeleteClick(position: Int)
}
fun setItemClickListener(itemClicker: ItemClicker) {
mListener = itemClicker
}
}
and then change your Flow observing method to this:
numberViewModel.numbers().observe(viewLifecycleOwner) { listN ->
if (listN.isNotEmpty()) {
val adapter = PhonesAdapter(requireContext(), listN)
binding.listPhones.adapter = adapter
adapter.setItemClickListener(object : PhonesAdapter.ItemClicker {
override fun onDeleteClick(position: Int) {
Toast.makeText(requireContext(), "Contact delete ${listN[position].contactName}", Toast.LENGTH_SHORT).show()
numberViewModel.deletenumber(listN[position])
}
})
} else {
val adapter = PhonesAdapter(requireContext(), listN)
binding.listPhones.adapter = adapter
}
}
Use adapter.notifyDataSetChanged() if necessary.

Kotlin problem with Spinner inside Fragment

I have a problem with the spinner inside a fragment. The spinner is filled with data, but when I select an item I don't see logs, and in the spinner, it does not select elements. When I used nearly the same code as an activity it worked (Just changed the context to this in the adapter)
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_edit_stoper, container, false)
val tagSpinner = view.findViewById<Spinner>(R.id.editSpinner)
val items: MutableList<String> = ArrayList("a","b","c")
tagSpinner.adapter = ArrayAdapter(this.requireActivity(), android.R.layout.simple_spinner_item, items) as SpinnerAdapter
tagSpinner.onItemSelectedListener = this
return view
}
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
Log.d(TAG,"OnItemSelected: $type")
}
override fun onNothingSelected(parent: AdapterView<*>?) {
Log.d(TAG,"error")
}
}
Is your fragment really a listener for spinner?
Write a custom listener and use that instead of your fragment.
inner class SpinnerStateChangeListener : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
// do sth here
}
override fun onNothingSelected(parent: AdapterView<*>?) {
// do sth here
}
}
Now you can set your listener like this:
tagSpinner.onItemSelectedListener = SpinnerStateChangeListener()
Try moving your implementation from Fragment directly to spinner. remove override from class and instead of
tagSpinner.onItemSelectedListener = this
do
tagSpinner.onItemSelectedListener = object :AdapterView.OnItemSelectedListener{
override fun onNothingSelected(parent: AdapterView<*>?) {
Log.d(TAG,"error")
}
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
Log.d(TAG,"OnItemSelected: $type")
}
}
The solution is to add requireActivity().applicationContext in the adapter to change the activityFragment to a context:
...
val items: MutableList<String> = ArrayList("a","b","c")
tagSpinner.adapter = ArrayAdapter(requireActivity().applicationContext, android.R.layout.simple_spinner_item, items) as SpinnerAdapter
tagSpinner.onItemSelectedListener = this
...

How do I make each ListView element create a unique activity [Android Studio - Kotlin]

I'm new to Android Development and Kotlin, so any help would be greatly appreciated.
So I've created an app in which there's a ListView which, once clicked, takes you to a new activity. However, for every element in the ListView, it takes me to the same activity. How do I change it so that every element takes me to a unique activity?
Here's my code so far (not all of it, the important bits, but please let me know if you'd like to see more)
MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val listView = findViewById<ListView>(R.id.main_ListView)
listView.adapter = MyCustomAdapter(this) // custom adapter --> tells list what to render
listView.isClickable = true
listView.onItemClickListener = AdapterView.OnItemClickListener { _, _, _, _ ->
setContentView(R.layout.activity_uni_detail)
}
}
}
private class MyCustomAdapter(context: Context): BaseAdapter() {
private val mContext: Context = context
private val nameOfUni = arrayListOf<String>(
"University of Toronto", "University of Waterloo", "McMaster University"
)
// responsible for rows
override fun getCount(): Int {
return nameOfUni.size
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getItem(position: Int): Any {
return "TEST STRING"
}
// responsible for rendering out each row
override fun getView(position: Int, convertView: View?, viewGroup: ViewGroup?): View {
val layoutInflater = LayoutInflater.from(mContext)
val rowMain = layoutInflater.inflate(R.layout.row_main, viewGroup, false)
val uniNameTextView = rowMain.findViewById<TextView>(R.id.uniName)
uniNameTextView.text = nameOfUni.get(position)
return rowMain
}
}
This is not a good implementation .First of all you should implement onClickListener in your adapter. for example on uniNameTextView not on the hole list. For the details activity you should not create a unique activity for every item , you must create one activity and for every item that is clicked ,you send the details to the activity.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val listView = findViewById<ListView>(R.id.main_ListView)
listView.adapter = MyCustomAdapter(this) // custom adapter --> tells list what to render
}
private class MyCustomAdapter(context: Context,onClick:OnClick): BaseAdapter() {
private val mContext: Context = context
private val nameOfUni = arrayListOf<String>(
"University of Toronto", "University of Waterloo", "McMaster University"
)
// responsible for rows
override fun getCount(): Int {
return nameOfUni.size
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getItem(position: Int): Any {
return "TEST STRING"
}
// responsible for rendering out each row
override fun getView(position: Int, convertView: View?, viewGroup: ViewGroup?): View {
val layoutInflater = LayoutInflater.from(mContext)
val rowMain = layoutInflater.inflate(R.layout.row_main, viewGroup, false)
val uniNameTextView = rowMain.findViewById<TextView>(R.id.uniName)
uniNameTextView.text = nameOfUni.get(position)
uniNameTextView.setOnClickListener{
////////////////////////// here
val intent = Intent(this, DetailsActivity::class.java)
intent.putExtra("samplename", nameOfUni.get(position))
startActivity(intent)
}
return rowMain
}
}
DetailActivity:
class DetailActivity :AppCompact() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_details)
val ss:String = intent.getStringExtra("samplename")
text_view_detail.text=ss
}
}

Android Spinner , set different value onItemselected

I want to set different values to a spinner when an item is selected, I set a list of country namse concatenate by country codes, on item selected event.
I want to set only the country code on view, but there is no method to set that value.
countryCodeSpinner.onItemSelectedListener = object : AdapterView.OnItemClickListener,
AdapterView.OnItemSelectedListener {
override fun onItemClick(
parent: AdapterView<*>?,
view: View?,
position: Int,
id: Long
) {
}
override fun onNothingSelected(parent: AdapterView<*>?) {
}
override fun onItemSelected(
parent: AdapterView<*>?,
view: View?,
position: Int,
id: Long
) {
countryCode = codesList[position]
}
}
You can do as following:
spinnerRangeForMap.onItemSelectedListener =
object : AdapterView.OnItemSelectedListener {
override fun onNothingSelected(parent: AdapterView<*>?) {
}
override fun onItemSelected(
parent: AdapterView<*>?,
view: View?,
position: Int,
id: Long
) {
if (position != 0) {
//Your code
}
}
}
and for item selected in spinner you can get as below:
spinnerRangeForMap.selectedItem.toString()
I added this code to get the view of the spinner and edit it after selecting :
override fun onItemSelected(
parent: AdapterView<*>?,
view: View?,
position: Int,
id: Long
) {
if (position > 0) {
val code = codesList[position]
view!!.findViewById<TextView>(android.R.id.text1).text =
"+" + code.split("+")[1]
countryCode = code
}}

Android Spinner out of memory on select

I want to use a Spinner inside my Dialog. The Spinner appears and contains the data i want to show. But as soon as i select one of the items, memory usage shoots up and i end up getting an out of memory Exception. In logcat the first entry after selectin the item is D/AndroidRuntime: Shutting down VM. I have no stacktraces whatsoever. Only some info output from the gc and two warnings about throwing an OOM.
class SearchTypeSpinner(context: Context, attributeSet: AttributeSet? = null): LinearLayout(context, attributeSet), AdapterView.OnItemSelectedListener {
private val types: List<String>
private val mapping: MutableMap<String, Int>
private val spinner: Spinner
init {
types = context.resources.getStringArray(R.array.filter_types).asList()
spinner = Spinner(context)
spinner.adapter = Adapter()
spinner.onItemSelectedListener = this
spinner.layoutParams = ViewGroup.LayoutParams(context, attributeSet)
addView(spinner)
}
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {}
override fun onNothingSelected(parent: AdapterView<*>?) {}
private inner class Adapter: ArrayAdapter<String>(context, android.R.layout.simple_spinner_item) {
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
val view = TextView(context)
view.layoutParams = LayoutParams(MATCH_PARENT, WRAP_CONTENT)
view.text = getTypeNameAtPosition(position)
return view
}
override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup?): View {
return getView(position, convertView, parent)
}
override fun getCount(): Int {
return types.size
}
}
}
Please let me know if i can provide additional information and thanks in advance.

Categories

Resources