RecyclerView view doesn't change using background_selector - android-recyclerview

I'm Trying to toggle item background color upon item selection.
I can see it's logic is working yet the background wouldn't change.
The log prints show the selctions indeed work, yet the background not.
From background_selector:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#android:color/holo_green_light" android:state_pressed="false" android:state_selected="true" />
<item android:drawable="#android:color/holo_purple" android:state_selected="false" />
</selector>
from task_row.xml:
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
app:cardCornerRadius="3dp"
app:cardElevation="3dp"
android:id="#+id/tasksCardView"
android:background="#drawable/background_selector"
app:cardUseCompatPadding="true">
From Adapter code:
class MyTasksAdapter (
val arrayList: ArrayList<Task>,
val selectedItemsList: ArrayList<Task>,
val deletedItemsList: ArrayList<String>) :
RecyclerView.Adapter<MyTasksAdapter.ViewHolder>() {
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
private var cardView: CardView = itemView.tasksCardView
private val selectedItems = SparseBooleanArray()
override fun onClick(view: View) {
if (selectedItems[adapterPosition, false]) {
selectedItems.delete(adapterPosition)
cardView.isSelected = false
Log.d("Item selected AA", "position: $position")
}
else {
selectedItems.put(adapterPosition, true)
view.isSelected = true
Log.d("Item selected BB", "position: $position")
}
}
init {
itemView.setOnClickListener(this)
}
Tried also changing cardview to view, but it didn't help either.
class MyTasksAdapter (
val arrayList: ArrayList<Task>,
val selectedItemsList: ArrayList<Task>,
val deletedItemsList: ArrayList<String>) :
RecyclerView.Adapter<MyTasksAdapter.ViewHolder>() {
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
//private lateinit var item: ClipData.Item
private var cardView: CardView = itemView.tasksCardView
private val selectedItems = SparseBooleanArray()
override fun onClick(view: View) {
if (selectedItems[adapterPosition, false]) {
selectedItems.delete(adapterPosition)
view.isSelected = false
Log.d("Item selected AA", "position: $position")
}
else {
selectedItems.put(adapterPosition, true)
view.isSelected = true
Log.d("Item selected BB", "position: $position")
}
}
init {
itemView.setOnClickListener(this)
}
Appreciate your kind help.

Working now.
Moved it to the relative_layout header: instead of cardview_layout header
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
app:cardCornerRadius="3dp"
app:cardElevation="3dp"
android:id="#+id/tasksCardView"
android:hapticFeedbackEnabled="true"
app:cardUseCompatPadding="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
**android:background="#drawable/background_selector"**
android:padding="16dp">

Related

Artefacts when implementing expandable items in RecyclerView

I'm trying to make a simple RecyclerView with expandable items using Kotlin. Basically a list of bins which expand out to show descriptions of what should go in them. I tried to follow the Android Studio Recycler View example as closely as possible. The problem is when I expand each item, some artefacts would show.
Unexpanded view
Expanded view
Note: The expanded view is the result of pressing on "Recycling Bin", the artefact is made up of the bin's description text and also "Garden Waste Bin" somehow being duplicated.
Below is my implementation
Adapter class
class BinAdapter(private val dataSet: List<Bin>) : RecyclerView.Adapter<BinViewHolder>() {
var expandedPosition = -1
var previousExpandedPosition = -1
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BinViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.bin_row_item, parent, false)
return BinViewHolder(view)
}
override fun onBindViewHolder(viewHolder: BinViewHolder, position: Int) {
viewHolder.itemView.isActivated
viewHolder.titleView.text = dataSet[position].name
viewHolder.descriptionView.text = dataSet[position].description
val isExpanded = position == expandedPosition
viewHolder.descriptionView.visibility = if (isExpanded) View.VISIBLE else View.GONE
viewHolder.itemView.isActivated = isExpanded
if (isExpanded) {
previousExpandedPosition = position
}
viewHolder.itemView.setOnClickListener {
expandedPosition = if (isExpanded) -1 else position
notifyItemChanged(previousExpandedPosition)
notifyItemChanged(position)
}
}
override fun getItemCount() = dataSet.size
Fragment class
class BinLookupFragment : Fragment() {
private var _binding: FragmentBinLookupBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentBinLookupBinding.inflate(inflater, container, false)
binding.binRecyclerView.adapter = BinAdapter(BinList(resources))
return binding.root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
ViewHolder class
class BinViewHolder(itemView: View) : ViewHolder(itemView) {
val titleView: TextView
val descriptionView: TextView
init {
titleView = itemView.findViewById(R.id.titleView)
descriptionView = itemView.findViewById(R.id.descriptionView)
}
}
Row item layout
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/titleView"
android:layout_width="#dimen/bin_list_width"
android:layout_height="#dimen/bin_list_item_title_height"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<TextView
android:id="#+id/descriptionView"
android:layout_width="#dimen/bin_list_width"
android:layout_height="#dimen/bin_list_item_description_height"
app:layout_constraintTop_toBottomOf="#id/titleView"
app:layout_constraintStart_toStartOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
fragment layout
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/bin_recycler_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="200dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/>
</androidx.constraintlayout.widget.ConstraintLayout>
Has anyone come across this before or have some debugging tips?

Show and hide a View with a slide up/down animation android studio

I have a problem hiding the BottomNavigationView since there is a space left over and I don't know what to do in that case, I don't know what property to use so that the entire BottomNavigationView is hidden, I would appreciate any advice or solution to my problem
Activity_main.XML
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/body_container"
app:hideOnScroll="true"
android:background="#color/light_color"
tools:context=".navigation_bottom">
<com.google.android.material.bottomnavigation.BottomNavigationView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_margin="30dp"
android:elevation="2dp"
android:background="#drawable/round_corner"
app:menu="#menu/item_menu"
app:itemRippleColor="#android:color/transparent"
app:itemIconSize="30dp"
app:labelVisibilityMode="labeled"
app:itemTextColor="#drawable/text_selector"
app:itemIconTint="#drawable/item_selector"
app:layout_behavior="com.google.android.material.behavior.HideBottomViewOnScrollBehavior"
app:hideOnScroll="true"
android:layout_gravity="bottom"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Activity_navigation_bottom
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/body_container"
app:hideOnScroll="true"
android:background="#color/light_color"
tools:context=".navigation_bottom">
<com.google.android.material.bottomnavigation.BottomNavigationView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_margin="30dp"
android:elevation="2dp"
android:background="#drawable/round_corner"
app:menu="#menu/item_menu"
app:itemRippleColor="#android:color/transparent"
app:itemIconSize="30dp"
app:labelVisibilityMode="labeled"
app:itemTextColor="#drawable/text_selector"
app:itemIconTint="#drawable/item_selector"
app:layout_behavior="com.google.android.material.behavior.HideBottomViewOnScrollBehavior"
app:hideOnScroll="true"
android:layout_gravity="bottom"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
ScrollHandler.kt
class ScrollHandler : CoordinatorLayout.Behavior<BottomNavigationView>() {
override fun layoutDependsOn(
parent: CoordinatorLayout,
child: BottomNavigationView,
dependency: View
): Boolean {
return dependency is FrameLayout
}
override fun onStartNestedScroll(
coordinatorLayout: CoordinatorLayout,
child: BottomNavigationView,
directTargetChild: View,
target: View,
nestedScrollAxes: Int
): Boolean {
return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL
}
override fun onNestedPreScroll(
coordinatorLayout: CoordinatorLayout,
child: BottomNavigationView,
target: View,
dx: Int,
dy: Int,
consumed: IntArray
) {
if (dy < 0) {
showBottomNavigationView(child)
} else if (dy > 0) {
hideBottomNavigationView(child)
}
}
private fun hideBottomNavigationView(view: BottomNavigationView) {
view.animate().translationY(view.height.toFloat())
}
private fun showBottomNavigationView(view: BottomNavigationView) {
view.animate().translationY(0f)
}
}
MainActivity.kt
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private var bottomNavigationView: BottomNavigationView? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
bottomNavigationView = binding.space as BottomNavigationView
val layoutParams = bottomNavigationView!!.layoutParams as CoordinatorLayout.LayoutParams
layoutParams.behavior = ScrollHandler()
setContentView(binding.root)
initRecyclerView()
}
I don't know what to try

Android kotlin preferences spinner with values from arrays.xml

settings_activity.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/settings"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
root_preferences.xml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<ListPreference
android:dialogTitle="Select bluetooth adapter"
android:key="bluetoothName"
android:summary="Click to show a list to choose from"
android:title="Bluetooth adapter" />
<ListPreference
android:dialogTitle="Select units"
android:entries="#array/units_names"
android:entryValues="#array/units_values"
android:key="units"
android:summary="Click to show a list to choose from"
android:title="Units" />
</PreferenceScreen>
SettingsActivity.kt
class SettingsActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.settings_activity)
supportFragmentManager
.beginTransaction()
.replace(R.id.settings, SettingsFragment())
.commit()
supportActionBar?.setDisplayHomeAsUpEnabled(true)
}
class SettingsFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.root_preferences, rootKey)
}
}
}
arrays.xml
<resources>
<string-array name="units_values">
<item>miles</item>
<item>km</item>
</string-array>
<string-array name="units_names">
<item>miles and mpg</item>
<item>km and l/100km</item>
</string-array>
</resources>
MainActivity.kt
...
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.toolbar, menu);
return true;
}
override fun onOptionsItemSelected( item: MenuItem) : Boolean {
when (item.itemId) {
R.id.toolbar_item_settings -> {
val intent: Intent = Intent(this, SettingsActivity::class.java)
startActivity(intent)
return true
}
}
return true
}
...
Why are the array values not showing in the spinner?
It's because the list item text colour has defaulted to black.
It needs:
<item name="textColorAlertDialogListItem">#color/text</item>

Using recycleview in android

I read some document about using recyclingview for activity. Now i try to use recycleview to my fragment. the problem is my fragment look empty when i execute.
fragment:
class KategoriFragment : Fragment() {
var araclarKategori = ArrayList<AracMarka>()
private lateinit var galleryViewModel: GalleryViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
veriKaynaginiDoldur()
galleryViewModel =
ViewModelProviders.of(this).get(GalleryViewModel::class.java)
var root = inflater.inflate(R.layout.fragment_category, container, false)
veriKaynaginiDoldur()
var rvarackategori = root.findViewById(R.id.rvarackategori) as RecyclerView
var MyAdapter = AracMarkaAdapter(araclarKategori)
rvarackategori.adapter = MyAdapter
/
return root
}
fun veriKaynaginiDoldur(): ArrayList<AracMarka> {
var aracLogo = arrayOf(R.drawable.opellogo, R.drawable.chevroletlogo)
var aracismi = resources.getStringArray(R.array.arabaisim)
for (i in 0 until min(aracismi.size, aracLogo.size)) {
var eklenecekaracKategori = AracMarka(aracismi[i], aracLogo[i])
araclarKategori.add(eklenecekaracKategori)
}
return araclarKategori
}
}
I create an adapter. I think there is no problem on it.
adapter:
class AracMarkaAdapter(tumKategori: ArrayList<AracMarka>) :
RecyclerView.Adapter<AracMarkaAdapter.AracMarkaViewHolder>() {
var araclar = tumKategori
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AracMarkaViewHolder {
var inflater = LayoutInflater.from(parent.context)
var arackategori = inflater.inflate(R.layout.arac_kategori, parent, false)
return AracMarkaViewHolder(arackategori)
}
override fun getItemCount(): Int {
return araclar.size
}
override fun onBindViewHolder(holder: AracMarkaViewHolder, position: Int) {
holder.aracismi.text=araclar.get(position).aracAdi
holder.aracLogo.setImageResource(araclar.get(position).aracLogo)
}
class AracMarkaViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var teksatirKategori= itemView
var aracismi= teksatirKategori.tvaracAdi
var aracLogo=teksatirKategori.img_arac_sembol
}
}
fragment xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rvarackategori"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
So, when i click button, fragment opens but it is empty. Do you have any idea about it?
After modifying the data in your list in veriKaynaginiDoldur(), you need to call myAdapter.notifyDataSetChanged() so it knows to rebind the data. Or you could call veriKaynaginiDoldur() before you instantiate your adapter.
Edit: Your other error is in your for loop within veriKaynaginiDoldur(). You are making a range using the size of the araclarKategori list when it is still zero.
Instead of
for (i in 0..araclarKategori.size - 1)
use
for (i in 0 until min(aracLogo.size, aracismi.size))
you have to call this veriKaynaginiDoldur() function after the below
lines of code below I have mentioned please check
var rvarackategori = root.findViewById(R.id.rvarackategori) as RecyclerView
var MyAdapter = AracMarkaAdapter(araclarKategori)
rvarackategori.adapter = MyAdapter
veriKaynaginiDoldur()

Convert MainActivity with actionbar/toolbar and floatingaction button to Anko

I am trying to learn how to use Kotlin/Anko.
I have gone thru the examples here and also cloned the template project and can understand how to do some basic stuff, but as an exercise I wanted to convert this simple activity (generated from a blank activity in Android Studio and converted to Kotlin) to use Anko as well. There are not a lot of examples around for Anko, most are just copies of what is on the above referenced github page.
Can someone demonstrate how to go about and convert the following into Anko DSL?
MainActivity.kt
import android.os.Bundle
import android.support.design.widget.FloatingActionButton
import android.support.design.widget.Snackbar
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.Toolbar
import android.view.Menu
import android.view.MenuItem
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val toolBar = findViewById(R.id.toolbar) as Toolbar
setSupportActionBar(toolBar)
val fab = findViewById(R.id.fab) as FloatingActionButton
fab.setOnClickListener { view -> Snackbar.make(view, "Replace this with your own action", Snackbar.LENGTH_LONG).setAction("Action", null).show() }
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_main, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
val id = item.itemId
if (id == R.id.action_settings) {
println("settings clicked on ")
return true
}
return super.onOptionsItemSelected(item)
}
}
main_activity.xml
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="#style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<include layout="#layout/content_main" />
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="#dimen/fab_margin"
android:src="#android:drawable/ic_dialog_email" />
</android.support.design.widget.CoordinatorLayout>
content_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context="com.gmail.npnster.mykotlinfirstproject.MainActivity"
tools:showIn="#layout/activity_main">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:id="#+id/hello"
/>
</RelativeLayout>
menu_main.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.gmail.npnster.mykotlinfirstproject.MainActivity">
<item
android:id="#+id/action_settings"
android:orderInCategory="100"
android:title="#string/action_settings"
app:showAsAction="never" />
</menu>
You can use ankoView method to create Views without DSL methods inside DSL context.
For example, to create a NavigationView one can use
ankoView({ NavigationView(it) }) {
lparams(width = wrapContent, height = matchParent, gravity = Gravity.START)
// more initialization follows
}
This way you can instantiate FloatingActionButton and AppBarLayout, just call their constructors inside ankoView's first argument function. For your convenience, you can make yourself DSL-like functions like in the manual:
fun floatingActionButton(init: FloatingActionButton.() -> Unit) = ankoView({ FloatingActionButton(it) }, init)
Creating a Toolbar is even easier: there is a DSL toolbar method in org.jetbrains.anko.appcompat.v7.
When using Anko DSL, to include another layout, as you did with content_main, one can either use Anko include function or just write a function which will fill in a ViewGroup. You can use this template:
fun ViewGroup.myLayout() {
textView("123")
// more DSL code here
}
Then just call myLayout() inside some ViewGroup initializer.
I know it's a bit late answer, but I hope it helps someone. I did the layout this way (of course some styling is still needed):
class MainUI(val adapter: MainUIAdapter) : AnkoComponent<MainActivity> {
override fun createView(ui: AnkoContext<MainActivity>): View = with(ui) {
coordinatorLayout {
fitsSystemWindows = true
appBarLayout {
toolbar {
setTitleTextColor(Color.WHITE) // so far still needed
id = R.id.toolbar
}.lparams(width = matchParent, height = matchParent)
}.lparams(width = matchParent)
relativeLayout {
id = R.id.container
recyclerView { // just an example
id = R.id.recycler_view
adapter = this#MainUI.adapter
layoutManager = LinearLayoutManager(ctx)
}
}.lparams(width = matchParent, height = matchParent) {
behavior = ScrollingViewBehavior()
}
floatingActionButton {
onClick { doSomething() }
imageResource = R.drawable.ic_add_white_24dp // the plus sign
}.lparams {
gravity = Gravity.BOTTOM or Gravity.END
margin = dip(16)
}
}
}
}
and used in MainActivity like that:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
MainUI(MainUIAdapter(people)).setContentView(this)
toolbar = find<Toolbar>(R.id.toolbar)
setSupportActionBar(toolbar)
}