Views in custom view not inflating - android

I have a volume screen that I want the user to be able to inflate from anywhere in the app.
class VolumeScreen #JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : RelativeLayout(context, attrs, defStyleAttr) {
private var audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
fun inflate(context: Context) {
LayoutInflater
.from(context)
.inflate(R.layout.screen_volume, this, true)
initUI()
}
fun hide() {
this.visibility = View.GONE
}
private fun initUI() {
this.visibility = View.VISIBLE
TTSUtils.getInstance(context).speakText(resources.getString(R.string.volume_help))
val audioStream = AudioManager.STREAM_SYSTEM
var currentVolume = audioManager.getStreamVolume(audioStream)
val maxVolume = audioManager.getStreamMaxVolume(audioStream)
volumeLevelText.text = resources.getString(R.string.volume_percentage, currentVolume.times(10).toString())
increaseButton.setOnClickListener {
if (currentVolume < 10) {
currentVolume += 1
}
audioManager.setStreamVolume(audioStream, currentVolume, 0)
volumeLevelText.text = resources.getString(R.string.volume_percentage, currentVolume.times(10).toString())
}
decreaseButton.setOnClickListener {
if (currentVolume > 0) {
currentVolume -= 1
}
audioManager.setStreamVolume(audioStream, currentVolume, 0)
volumeLevelText.text = resources.getString(R.string.volume_percentage, currentVolume.times(10).toString())
}
volumeContinueButton.setOnClickListener {
this.hide()
}
}
}
.xml:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<RelativeLayout android:layout_width="768px"
android:layout_height="840px"
android:background="#color/main_background">
<TextView
android:text="#string/volume"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="78px"
android:textAppearance="#style/ScreenTitle"/>
<TextView
android:text="#string/adjust_volume"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="220px"
android:textAppearance="#style/ScreenSubtitle"/>
<TextView
android:text="#string/volume_percentage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="350px"
android:textAppearance="#style/Amount"
android:id="#+id/volumeLevelText"/>
<LinearLayout android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginBottom="171px"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true">
<ImageView
android:src="#drawable/connector_line"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
/>
<Button android:layout_width="348px"
android:layout_height="104px"
android:text="#string/decrease_volume"
android:gravity="left|center_vertical"
android:textAppearance="#style/SelectionButtonText"
android:background="#drawable/button_background_coral"
android:drawableRight="#drawable/ic_remove_81dp"
android:paddingRight="29px"
android:paddingLeft="30px"
android:id="#+id/decreaseButton"
/>
</LinearLayout>
<LinearLayout android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginBottom="171px"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true">
<Button android:layout_width="348px"
android:layout_height="104px"
android:text="#string/increase_volume"
android:gravity="left|center_vertical"
android:textAppearance="#style/SelectionButtonText"
android:background="#drawable/button_background_coral"
android:drawableRight="#drawable/ic_add_81px"
android:paddingRight="29px"
android:paddingLeft="30px"
android:id="#+id/increaseButton"
/>
<ImageView
android:src="#drawable/connector_line"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
/>
</LinearLayout>
<LinearLayout android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginBottom="31px"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true">
<Button android:layout_width="348px"
android:layout_height="104px"
android:text="#string/cont"
android:textAppearance="#style/SelectionButtonText"
android:background="#drawable/button_background_olive"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:id="#+id/volumeContinueButton"
/>
<ImageView
android:src="#drawable/connector_line"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
/>
</LinearLayout>
In activity's .xml:
<group.flowbird.indygotvm.views.VolumeScreen
android:id="#+id/volumeScreen"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="80px"
android:layout_marginBottom="104px"
android:elevation="1px"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent">
</group.flowbird.indygotvm.views.VolumeScreen>
The first time inflate() is called, the views are updated according to the code inside of initUI(). But if it is re-inflated after hide() is called, none of that stuff happens, even though initUI() is called again. How do I make sure the view is being re-rendered or assigned its onClickListener() each time inflate() is called on it?

This view never is inflated because the init method do nothing. Try to use the init Kotlin constructor to inflate the view and init the UI:
init {
LayoutInflater
.from(context)
.inflate(R.layout.screen_volume, this, true)
initUI()
}
With the previous code, when the activity calls the setContentView method, the views are inflated including your custom view.
Use the constructor context in the inflate() method removing the context param. But if you don´t need to inflate this view programatically, then is not necessary this method.

Related

RecyclerView doesn't display all data

I am working on an application with multiple recycler views inside a fragment. Everything is working properly, except from one recycler view which doesn't display all data. I get the data after an API call, and I have already checked that they are loaded successfully. Any help would be much appreciated, thank you in advance!!
Here is the recycler view inside the fragment:
<?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="wrap_content"
android:background="#color/white"
tools:context=".ui.fragments.ExploreFragment">
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:fillViewport="true"
android:scrollbars="none">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rvExploreFragmentFeaturedProducts"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="30dp"
>
</androidx.recyclerview.widget.RecyclerView>
</RelativeLayout>
</ScrollView>
</RelativeLayout>
Here is the cardview which will be loaded repeatedly inside the recycler view, which is not properly displayed (only the image view and shapeable image view gets displayed):
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView 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:id="#+id/layoutFeaturedProductRowCardView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cardCornerRadius="10dp"
app:cardElevation="5dp"
android:layout_marginBottom="40dp">
<RelativeLayout
android:id="#+id/rlFeaturedProducts"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:background="#drawable/rounded_frame_recommproducts_explore">
<com.google.android.material.imageview.ShapeableImageView
android:id="#+id/ivFeaturedProduct"
android:layout_width="335dp"
android:layout_height="180dp"
android:scaleType="centerCrop"
app:shapeAppearanceOverlay="#style/rounded_cornersTop"
tools:src="#tools:sample/backgrounds/scenic" />
<ImageView
android:id="#+id/imageViewFavorite"
android:layout_width="wrap_content"
android:layout_height="26dp"
android:layout_alignEnd="#id/ivFeaturedProduct"
android:layout_marginTop="20dp"
android:layout_marginEnd="20dp"
android:src="#drawable/ic_favorite_up"/>
<TextView
android:id="#+id/textViewProductTitle"
android:layout_width="295dp"
android:layout_height="wrap_content"
android:layout_below="#+id/ivFeaturedProduct"
android:layout_marginStart="15dp"
android:layout_marginTop="20dp"
android:fontFamily="#font/semibold"
android:textColor="#color/colorPrimaryDarkV2"
android:textSize="16sp" />
<TextView
android:id="#+id/textViewCategory"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/textViewProductTitle"
android:layout_alignStart="#id/textViewProductTitle"
android:fontFamily="#font/semibold"
android:textSize="12sp"/>
<TextView
android:id="#+id/textViewDuration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/textViewCategory"
android:layout_alignStart="#id/textViewCategory"
android:layout_marginTop="20dp"
android:drawablePadding="10dp"
android:fontFamily="#font/medium"
android:text="#string/durationlabel"
android:textColor="#color/colorPrimaryLightV2"
android:textSize="12sp"
app:drawableLeftCompat="#drawable/ic_time_icon" />
<TextView
android:id="#+id/textViewDurationValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toEndOf="#id/textViewDuration"
android:layout_alignBaseline="#id/textViewDuration"
android:layout_marginStart="2dp"
android:fontFamily="#font/medium"
android:textColor="#color/colorPrimaryDarkV2"
android:textSize="12sp"/>
<TextView
android:id="#+id/textViewLanguage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/textViewDuration"
android:layout_alignStart="#id/textViewDuration"
android:layout_marginTop="12dp"
android:drawablePadding="10dp"
android:fontFamily="#font/medium"
android:text="#string/languagelabel"
android:textColor="#color/colorPrimaryLightV2"
android:textSize="12sp"
app:drawableLeftCompat="#drawable/ic_audio_icon" />
<TextView
android:id="#+id/textViewLanguageValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toEndOf="#id/textViewLanguage"
android:layout_alignBaseline="#id/textViewLanguage"
android:layout_marginStart="2dp"
android:fontFamily="#font/medium"
android:textColor="#color/colorPrimaryDarkV2"
android:textSize="12sp" />
<TextView
android:id="#+id/textViewThreeSixtyImages"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/textViewLanguage"
android:layout_alignStart="#id/textViewLanguage"
android:layout_marginTop="12dp"
android:drawablePadding="10dp"
android:fontFamily="#font/medium"
android:text="#string/theesixtylabel"
android:textColor="#color/colorPrimaryLightV2"
android:textSize="12sp"
app:drawableLeftCompat="#drawable/ic_images_icon"
android:visibility="gone"/>
<TextView
android:id="#+id/ratingLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="#id/ratingValue"
android:layout_toStartOf="#id/ratingValue"
android:layout_marginTop="2dp"
android:drawablePadding="10dp"
android:fontFamily="#font/semibold"
android:textColor="#color/colorPrimaryDarkV2"
android:textSize="14sp"
app:drawableLeftCompat="#drawable/ic_rating_small_tag" />
<TextView
android:id="#+id/ratingValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toStartOf="#id/ratingCount"
android:layout_alignBaseline="#id/ratingCount"
android:layout_marginEnd="2dp"
android:fontFamily="#font/semibold"
android:textColor="#color/colorPrimaryDarkV2"
android:textSize="14sp"
/>
<TextView
android:id="#+id/ratingCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/ivFeaturedProduct"
android:layout_alignTop="#id/textViewCategory"
android:layout_alignRight="#id/ivFeaturedProduct"
android:layout_marginEnd="15dp"
android:fontFamily="#font/semibold"
android:textColor="#color/colorPrimaryLightV2"
android:textSize="14sp" />
<TextView
android:id="#+id/priceLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/ratingCount"
android:layout_alignEnd="#id/ratingCount"
android:layout_marginTop="20dp"
android:fontFamily="#font/medium"
android:text="#string/fromLabel"
android:textColor="#color/colorPrimaryLightV2"
android:textSize="12sp" />
<TextView
android:id="#+id/salesValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignEnd="#id/priceLabel"
android:layout_below="#id/priceLabel"
android:layout_marginTop="2dp"
android:fontFamily="#font/medium"
android:textSize="12sp"
android:textColor="#color/colorPrimaryV2"
android:visibility="gone"/>
<TextView
android:id="#+id/priceValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/priceLabel"
android:layout_alignEnd="#id/priceLabel"
android:layout_marginTop="18dp"
android:fontFamily="#font/bold"
android:textColor="#color/colorPrimaryDarkV2"
android:textSize="18sp" />
<TextView
android:id="#+id/perPersonLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/priceValue"
android:layout_alignBaseline="#id/textViewThreeSixtyImages"
android:layout_alignEnd="#+id/priceValue"
android:fontFamily="#font/medium"
android:layout_marginBottom="24dp"
android:text="#string/perPersonLabel"
android:textColor="#color/colorPrimaryLightV2"
android:textSize="12sp" />
</RelativeLayout>
</androidx.cardview.widget.CardView>
Then, here is the adapter giving the card view the values:
class ProductsAdapter(private val products: List<Product>) :
RecyclerView.Adapter<ProductsAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) : ViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.view_layout_featuredproduct_row, parent, false)
view.layoutParams.height = (parent.measuredWidth - 40)/2 + 30
view.requestLayout()
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bindProduct(products[position])
}
override fun getItemCount(): Int = products.size
class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
private val image = view.findViewById<ShapeableImageView>(R.id.ivFeaturedProduct)
private val featuredProductTitle = view.findViewById<TextView>(R.id.textViewProductTitle)
private val category = view.findViewById<TextView>(R.id.textViewCategory)
private val featuredProductDuration = view.findViewById<TextView>(R.id.textViewDurationValue)
private val language = view.findViewById<TextView>(R.id.textViewLanguageValue)
private val averageRating = view.findViewById<TextView>(R.id.ratingValue)
private val ratingcount = view.findViewById<TextView>(R.id.ratingCount)
private val pricevalue = view.findViewById<TextView>(R.id.priceValue)
private val context = view.context
private val resources = view.resources
fun bindProduct(product: Product) {
with(product) {
val uri = this.header_image
Picasso.get().load(uri).
placeholder( R.drawable.progress_animation ).
transform(ColorFilterTransformation(ContextCompat.getColor(context, R.color.colorOverlay))).
into(image)
val categoryHelper = this.sku
if (categoryHelper[0].equals('S')){
category.text = resources.getString(R.string.skipTheLineTours)
category.setBackgroundResource(R.drawable.label_skipthelinetour)
category.setTextColor(resources.getColor(R.color.colorSkipTheLineTourTxt))
}
if (categoryHelper[0].equals('A')){
category.text = resources.getString(R.string.audioTours)
category.setBackgroundResource(R.drawable.label_audiotour)
category.setTextColor(resources.getColor(R.color.colorAudioTourTxt))
}
if(categoryHelper[0].equals('V')){
category.text = resources.getString(R.string.virtualTours)
category.setBackgroundResource(R.drawable.label_virtualtour)
category.setTextColor(resources.getColor(R.color.colorVirtualTourTxt))
}
featuredProductTitle.text = this.title
featuredProductDuration.text = this.duration+" minutes"
language.text = languages.size.toString()+" languages"
//category.text = this.sku
averageRating.text = this.average_rating
ratingcount.text = "("+this.rating_count.toString()+")"
pricevalue.text = this.retail_price.toString()+"€"
}
}
}
}
And last but not least, here is the code generating the recycler view:
class ExploreFragment : Fragment() {
private lateinit var viewProductsAdapter: ProductsAdapter
private val model: ProductsViewModel by activityViewModels()
private lateinit var featuredProducts: MutableList<Product>
private lateinit var viewManager : LinearLayoutManager
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_explore, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
loadFeaturedProducts()
}
private fun loadFeaturedProducts() {
if(!NetworkState().isNetworkAvailable(this#ExploreFragment.context!!.applicationContext)){
return;
}
featuredProducts = mutableListOf()
val recyclerView = rvExploreFragmentFeaturedProducts
viewProductsAdapter = ProductsAdapter(this.featuredProducts)
viewManager = LinearLayoutManager(this.context, LinearLayoutManager.VERTICAL, false)
recyclerView.layoutManager = viewManager
//recyclerView.setHasFixedSize(true)
recyclerView.adapter = viewProductsAdapter
Timber.i("Fragment: load featured products")
model.getProducts().observe(viewLifecycleOwner, { products->
if(products.status == Status.SUCCESS) {
this.featuredProducts.addAll(products.data!!)
viewProductsAdapter.notifyDataSetChanged()
}else {
Timber.i("Featured Products message: "+products.message)
Snackbar.make(view!!, "Cannot load featured products! Error:"+products.message, Snackbar.LENGTH_LONG).show()
}
})
}
}
Thank you for your answers - I figured out my mistake:
I couldn't see anything that was below the ImageView inside my CardView, even though it loaded correctly.
On ProductsListAdapter I forgot to remove an unnecessary calculation:
view.layoutParams.height = (parent.measuredWidth - 40)/2 + 30
view.requestLayout()
which was what caused the problem!
Instead of using the following code:
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rvExploreFragmentFeaturedProducts"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="30dp"
>
</androidx.recyclerview.widget.RecyclerView>
Please update it with
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rvExploreFragmentFeaturedProducts"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="30dp"
/>
the Reason you are not getting data is tags! You are not closing tag of Recycler View instead you are creating a new scope to add more things in it like we do with Layouts.
So remove : </androidx.recyclerview.widget.RecyclerView> and add "/" to the closing tag of recycler view or just simply copy and paste my code above

RadioButton items not resetting in RecyclerView

This has been asked before but those solutions didn't help me out. I have a RecyclerView that is scrollable and only partially visible on the screen at any one time. It holds a list of RadioButtons and some text related to each item. When you click on a RadioButton, the last button selected prior to this one should turn off. It does not. Each button you click gets selected and the other ones that you selected before stay selected as well.
It's set up like this:
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#color/white"
tools:context=".ui.SettingsActivity">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/video_settings"
android:textColor="#color/black"
android:textStyle="bold"
android:textSize="#dimen/clickableTextSize"
android:layout_alignParentStart="true"
/>
</RelativeLayout>
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="match_parent"
android:weightSum="100"
android:gravity="bottom"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="15"
android:paddingStart="15dp"
android:paddingEnd="15dp"
android:text="#string/set_resolution_and_fps"
android:textSize="#dimen/history_text_size"
android:gravity="center_vertical"
android:background="#color/grey_200"
android:textColor="#color/black"
/>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv_video_resolution"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="80"
android:layout_marginTop="5dp"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/submitVideoSettings"
android:text="#string/submit"
android:layout_marginBottom="5dp"
android:textColor="#color/black"
android:layout_gravity="center|bottom"
/>
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.appcompat.widget.LinearLayoutCompat>
The recycler looks like this:
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:orientation="horizontal"
xmlns:android="http://schemas.android.com/apk/res/android">
<RadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/resolutionRVRadioButton"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/resolutionRVTV"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:text="#string/at_symbol"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/framesPerSecondRVTV"
android:layout_marginStart="5dp"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/fps"
/>
</androidx.appcompat.widget.LinearLayoutCompat>
The code for the adapter looks like this.
class ResolutionRVAdapter(private val sharedNavAndMenuViewModel: SharedNavAndMenuViewModel,
private val lastResolutionSelected: String,
private val capabilityDataList: List<CameraCapabilitySpecificFPS>) : RecyclerView.Adapter<CameraResolutionRVAdapter.ViewHolder>(){
private var lastCheckedPosition = -1
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CameraResolutionRVAdapter.ViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.camera_resolution_recycler_item, parent, false)
val viewHolder = ViewHolder(v)
Timber.i("Added viewHolder: ${viewHolder.resolutionText.text}")
return ViewHolder(v)
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
val resolutionRadioButton : RadioButton = itemView.findViewById(R.id.resolutionRVRadioButton)
val resolutionText : TextView = itemView.findViewById(R.id.resolutionRVTV)
val framesPerSecondText : TextView = itemView.findViewById(R.id.framesPerSecondRVTV)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val child = capabilityDataList[position]
Timber.i("onBindViewHolder currently working with resolution ${child.resolution} range of $child.range")
holder.resolutionText.text = child.resolution.toString()
holder.framesPerSecondText.text = child.fps
Timber.d("OnBindViewholder and lastResolutionSelected = $lastResolutionSelected")
if(lastResolutionSelected.isEmpty()) {
if(position == 0) {
holder.resolutionRadioButton.isChecked = true
Timber.i("No last resolution was selected. Setting index 0 to true")
}
} else if(lastResolutionSelected == holder.resolutionText.text.toString()) {
Timber.i("An old resolution of ${holder.resolutionText.text} was selected. Setting index $position to true")
holder.resolutionRadioButton.isChecked = true
}
holder.resolutionRadioButton.setOnClickListener {
Timber.i("Index hit was: $position resolution at that index was: ${holder.resolutionText.text}")
if(holder.resolutionRadioButton.isChecked) {
//Button was already checked...must be the same button hit before...nothing to do
} else {
holder.resolutionRadioButton.isChecked = true
runOnUiThread {
notifyItemChanged(lastCheckedPosition)
notifyItemChanged(position)
}
lastCheckedPosition = position
}
}
}
override fun getItemCount(): Int {
return capabilityDataList.size
}
}
Can anyone tell me what it is I'm doing wrong?

Viewholder clickable area has margin bottom that's not defined

Here is how the problem looks -
And here is my ViewHolder code -
<?xml version="1.0" encoding="utf-8"?>
<layout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/groups_list_root_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:drawable/list_selector_background"
android:clickable="true"
android:focusable="true"
android:orientation="horizontal"
android:padding="10dp">
<ImageView
android:id="#+id/groups_list_group_image"
android:layout_width="60dp"
android:layout_gravity="center"
android:layout_height="60dp"
tools:src="#drawable/multi_user_group" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="14dp"
android:layout_gravity="center"
android:orientation="vertical">
<TextView
android:id="#+id/groups_list_group_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#color/black"
android:textSize="16sp"
tools:text="Galipoly 38 Apt" />
<TextView
android:id="#+id/groups_list_group_members"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxEms="15"
android:maxLines="1"
tools:text="Alon Shlider, Dekel Aslan, Omer..."
android:textColor="#color/colorPrimary"
android:textSize="16sp" />
<TextView
android:id="#+id/groups_list_group_open_tasks"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="9 Open Tasks"
android:textColor="#color/orange"
android:textSize="16sp" />
</LinearLayout>
</LinearLayout>
</layout>
class GroupsListViewHolder(private val binding: GroupsListViewHolderBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(model: GroupModel, onClick: (model: GroupModel) -> Unit) {
binding.groupsListGroupName.text = model.groupName
binding.groupsListGroupMembers.text = TextUtils.join(", ", model.usersFullNames)
if (model.tasksCounter < 1) {
binding.groupsListGroupOpenTasks.setAsGone()
} else {
binding.groupsListGroupOpenTasks.setAsVisible()
binding.groupsListGroupOpenTasks.text = model.tasksCounter.toString()
.plus(" ")
.plus(TeamitApplication.context!!.getString(R.string.ongoing_tasks))
.plus(TeamitApplication.context!!.getString(R.string.dot))
}
if (model.usersFullNames.size == 1) {
binding.groupsListGroupImage.setImageResource(R.drawable.single_user_group)
} else {
binding.groupsListGroupImage.setImageResource(R.drawable.multi_user_group)
}
binding.groupsListRootLayout.setOnClickListener {
onClick(model)
}
}
}
private fun initAdapter() {
fetchGroupData { groupModelList ->
if (groupModelList.isEmpty()) {
binding.groupsListNoGroupsMessageTitle.setAsVisible()
binding.groupsListNoGroupsMessageDescription.setAsVisible()
return#fetchGroupData
}
binding.groupsListNoGroupsMessageTitle.setAsGone()
binding.groupsListNoGroupsMessageDescription.setAsGone()
adapter.submitList(null)
adapter.submitList(groupModelList)
binding.groupsListRecyclerview.setAdapterWithItemDecoration(requireContext(), adapter)
}
}
fun <T, VH : RecyclerView.ViewHolder> RecyclerView.setAdapterWithItemDecoration(context: Context, adapter: ListAdapter<T, VH>) {
this.adapter = adapter
this.setHasFixedSize(true)
this.layoutManager = LinearLayoutManager(context)
this.addItemDecoration(DividerItemDecoration(context, DividerItemDecoration.VERTICAL))
}
As you can see, the click area has some margin bottom that I can't understand why happens. Sometimes it happens and sometimes it doesn't and I can't figure out what wrong.
As for the extension function that I am using - I am using it for the entire application
In your first LinearLayout you have defined android:padding="10dp". I assume this causes the unwanted margin.

Handling click events in android kotlin: setOnClickListener only works when double-clicked

I have a button in a DialogFragment to go back to another activity. But it only works when double-clicked. I'm running out of ideas. In my XML file, I've already tried the following (combined in different ways, but none of them worked)
My whole fragment XML file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="600dp"
android:layout_height="500dp"
android:layout_gravity="center"
android:background="#drawable/bg_rounded_white"
android:gravity="center"
android:orientation="vertical"
android:padding="#dimen/vertical_margin">
<TextView
android:id="#+id/tv_payment_done_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/vertical_margin"
android:gravity="center_horizontal"
android:text="#string/payment_approved_title"
android:textColor="#color/bg_color"
android:textSize="#dimen/text_large"
android:textStyle="bold" />
<TextView
android:id="#+id/tv_payment_message"
android:layout_width="550dp"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/vertical_margin"
android:gravity="center_horizontal"
android:minHeight="100dp"
android:text="Payment done!"
android:textColor="#color/black_overlay"
android:textSize="#dimen/text_medium"
android:textStyle="normal" />
<LinearLayout
android:layout_width="600dp"
android:layout_height="80dp"
android:layout_marginTop="46dp"
android:clickable="false"
android:focusable="false"
android:gravity="center"
android:orientation="horizontal">
<Button
android:id="#+id/rpv_btn_no_payment_done"
android:layout_width="250dp"
android:layout_height="?android:attr/actionBarSize"
android:background="#drawable/bg_rounded_light_blue"
android:duplicateParentState="true"
android:text="#string/txt_btn_no"
android:textAllCaps="false"
android:textColor="#color/white_text_color"
android:textSize="#dimen/text_medium"
android:textStyle="bold"
android:visibility="gone" />
<Button
android:id="#+id/rpv_btn_yes_payment_done"
android:layout_width="250dp"
android:layout_height="?android:attr/actionBarSize"
android:layout_marginLeft="#dimen/vertical_margin"
android:background="#drawable/bg_rounded_light_blue"
android:clickable="true"
android:focusable="true"
android:focusableInTouchMode="true"
android:focusedByDefault="true"
android:text="#string/txt_btn_exit"
android:textAllCaps="false"
android:textColor="#color/white_text_color"
android:textSize="#dimen/text_medium"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
As for my DialogFragment, I've tried to put my setOnClickListener inside the onViewCreated() method, and then inside the onStart() and after inside the onResume() methods. It keeps working only when double-clicked. I also have a timer that makes the dialog disappear after 10 secs and then it leads me to the activity I want anyway, so it isn't so much of a problem, but I really need and want to fix it. If I set the timer to 5 secs or lower, of course, it gives the impression that the button works when clicked once, but it actually doesn't.
class PaymentDoneDialogFragment : DialogFragment() {
private lateinit var mYesBtn: Button
private lateinit var mActionYes: () -> Unit
override fun onViewCreated(view: View, #Nullable savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
dialog.setCanceledOnTouchOutside(false)
dialog.window.requestFeature(Window.FEATURE_NO_TITLE)
dialog.window.setDimAmount(.85f)
dialog.window.setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)
dialog.setCancelable(false)
dialog.setCanceledOnTouchOutside(false)
dialog.window.decorView.systemUiVisibility = activity?.window!!.decorView.systemUiVisibility
dialog.window.clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)
mDialogTitle = view.find(R.id.tv_payment_done_title)
if (mTitle != null) {
mDialogTitle.text = mTitle
}
mYesBtn = view.find(R.id.rpv_btn_yes_payment_done)
if (mYesTitle != null) {
mYesBtn.text = mYesTitle
}
mYesBtn.setOnClickListener {
if (mMessage == null) {
(activity as PaymentActivity).nextScreensaverActivity()
} else {
mActionYes()
}
activity?.supportFragmentManager?.beginTransaction()?.remove(this)?.commit()
}
if (mMessage != null) {
mMessageTextView = view.find(R.id.tv_payment_message)
mMessageTextView?.text = mMessage
mNoBtn = view.find(R.id.rpv_btn_no_payment_done)
if (mNoTitle != null)
mNoBtn.text = mNoTitle
mNoBtn.visibility = View.VISIBLE
mNoBtn.setOnClickListener {
mActionNo()
activity?.supportFragmentManager?.beginTransaction()?.remove(this)?.commit()
}
}
}
Does anyone have some clue?
You should remove android:clickable="false" and android:focusable="false" from LinearLayout child

Showing Android Wear style AlertDialog

I'm looking for a way to recreate the alert dialog in the Setting application of Android Wear:
Which is swipe to dismissable.
But instead, what I got is this:
Just a barebone Android dialog. How can I show the AlertDialog in the Settings.apk style? (Which I think must be default for Android Wear application)
I found no default way to do this, also setting a custom view to an AlertDialog did not look good. You can still try though, maybe a different Theme works.
What I did was create a new Activity and create my own layout which looks like this:
<?xml version="1.0" encoding="utf-8"?>
<android.support.wearable.view.BoxInsetLayout
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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:padding="10dp"
app:layout_box="all">
<TextView
android:id="#+id/tv_longtext"
android:layout_width="match_parent"
android:layout_height="0sp"
android:layout_weight="1"
android:fontFamily="sans-serif-condensed"
android:gravity="bottom"
android:padding="5sp"
android:text="Ambient screen reduces battery life."
android:textSize="16sp" />
<TextView
android:id="#+id/tv_question"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-condensed"
android:gravity="center_horizontal|top"
android:paddingBottom="15sp"
android:paddingTop="5sp"
android:text="Turn on?"
android:textSize="18sp" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5sp">
<android.support.wearable.view.CircledImageView
android:id="#+id/btn_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left|bottom"
android:src="#drawable/ic_cross"
app:circle_color="#AFAFAF"
app:circle_radius="25dp"
app:circle_radius_pressed="20dp" />
<android.support.wearable.view.CircledImageView
android:id="#+id/btn_ok"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right|bottom"
android:src="#drawable/ic_tick"
app:circle_color="#0EB695"
app:circle_radius="25dp"
app:circle_radius_pressed="20dp" />
</FrameLayout>
</LinearLayout>
</android.support.wearable.view.BoxInsetLayout>
It looks just like the confirmation screen from the settings. Maybe it still needs some tweaks, but I think this is the way to go.
I had a similar problem and indeed I didn't find a default way to do this. I tried to use AlertDialogs for WearOs and they don't look well, because even if you pass them a custom view, the AlertDialog class crops the layout in some unexpected ways.
How I ended up solving the problem is using the Dialog class (AlertDialog's parent class) and passing it a custom view. The Dialog class doesn't alter the layout and you can attach the dialog to an activity's lifespan (which is the idea of dialogs, creating a custom activity doesn't fit with this requirement).
So you could create a function like this inside your activity:
private void showDialog() {
Dialog dialog = new Dialog(this);
View myLayout = getLayoutInflater().inflate(R.layout.my_layout_id, null);
Button positiveButton = myLayout.findViewById(R.id.positive_button);
positiveButton.setOnClickListener(
v -> {
/* Your action on positive button clicked. */
}
);
Button negativeButton = myLayout.findViewById(R.id.negative_button);
negativeButton.setOnClickListener(
v -> {
/* Your action on negative button clicked. */
}
);
dialog.setContentView(myLayout);
dialog.show();
}
I created a similar fragment with custom layout like this:
Kotlin code:
/**
* Created by nmbinh87#gmail.com on 4/12/21.
*/
class ConfirmationDialog private constructor() : DialogFragment(R.layout.confirmation_dialog) {
var listener: Listener? = null
var longMessage: String = ""
var shortMessage = ""
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
tv_longtext.text = longMessage
tv_question.text = shortMessage
tv_longtext.visibility = if (longMessage.isEmpty()) View.GONE else View.VISIBLE
tv_question.visibility = if (shortMessage.isEmpty()) View.GONE else View.VISIBLE
btn_cancel.setSafeOnClickListener {
dismiss()
listener?.onCancel()
}
btn_ok.setSafeOnClickListener {
dismiss()
listener?.onConfirm()
}
}
override fun onStart() {
super.onStart()
val params = dialog?.window?.attributes
params?.width = WindowManager.LayoutParams.MATCH_PARENT
params?.height = WindowManager.LayoutParams.MATCH_PARENT
dialog?.window?.attributes = params as WindowManager.LayoutParams
dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT));
}
open class Listener {
fun onCancel() {
}
open fun onConfirm() {
}
}
companion object {
fun show(
fm: FragmentManager,
longMessage: String = "",
shortMessage: String = "",
listener: Listener
) {
val fragment = ConfirmationDialog()
fragment.longMessage = longMessage
fragment.shortMessage = shortMessage
fragment.listener = listener
fragment.show(fm, fm::class.simpleName)
}
}
}
Layout:
<?xml version="1.0" encoding="utf-8"?>
<android.support.wearable.view.BoxInsetLayout 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:background="#color/colorPrimaryDark"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:padding="10dp"
app:layout_box="all">
<TextView
android:id="#+id/tv_longtext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:fontFamily="sans-serif-condensed"
android:gravity="center"
android:padding="5sp"
android:textColor="#color/white"
android:textSize="16sp"
tools:text="Ambient screen reduces battery life." />
<TextView
android:id="#+id/tv_question"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-condensed"
android:layout_weight="1"
android:gravity="center"
android:paddingTop="5sp"
android:paddingBottom="15sp"
android:textColor="#color/white"
android:textSize="18sp"
tools:text="Turn on?" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5sp">
<android.support.wearable.view.CircledImageView
android:id="#+id/btn_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left|bottom"
android:src="#drawable/ic_cc_clear"
app:circle_color="#AFAFAF"
app:circle_radius="25dp"
app:circle_radius_pressed="20dp" />
<android.support.wearable.view.CircledImageView
android:id="#+id/btn_ok"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right|bottom"
android:src="#drawable/ic_cc_checkmark"
app:circle_color="#0EB695"
app:circle_radius="25dp"
app:circle_radius_pressed="20dp" />
</FrameLayout>
</LinearLayout>
</android.support.wearable.view.BoxInsetLayout>
Usage:
ConfirmationDialog.show(
childFragmentManager,
"",
"Turn alarm off?",
object : ConfirmationDialog.Listener() {
override fun onConfirm() {
super.onConfirm()
turnAlarm(false)
}
})

Categories

Resources