The items in my RecyclerView Grid are stretched automatically if the left item is shorter and the right item is taller or vice versa (2 grid spans) because I want to use layout_height="wrap_content". How to keep that left item from being stretched automatically? I still want to use the GridLayout style because in my case it is not suitable if using StaggeredGridLayout (because it is more suitable for photo galleries).
<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:background="#color/very_light_gray"
android:paddingBottom="61dp"
tools:context="Fragment">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
...
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv_explore_buyer_outlet"
android:layout_width="0dp"
android:layout_height="0dp"
android:clipToPadding="false"
android:overScrollMode="ifContentScrolls"
android:paddingEnd="#dimen/_20sdp"
android:paddingBottom="28dp"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:spanCount="2"
tools:ignore="RtlSymmetry"
tools:itemCount="18"
tools:listitem="#layout/item_grid" />
</androidx.constraintlayout.widget.ConstraintLayout
</androidx.coordinatorlayout.widget.CoordinatorLayout>
item_grid.xml
<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:layout_width="177dp"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/_14sdp"
android:layout_marginTop="#dimen/_14sdp"
android:layout_marginEnd="#dimen/_minus18sdp"
android:layout_marginBottom="-7dp"
android:clickable="true"
android:focusable="true"
android:foreground="?android:attr/selectableItemBackground"
app:cardCornerRadius="14dp"
app:cardElevation="1dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/iv_item_outlet_buyer_photo"
android:layout_width="match_parent"
android:layout_height="112dp"
android:importantForAccessibility="no"
android:scaleType="centerCrop"
android:src="#drawable/outlet10"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/tv_item_outlet_buyer_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginEnd="9dp"
android:background="#drawable/outlet_buyer_status_open_label"
android:fontFamily="#font/notosansjp_medium"
android:gravity="center"
android:includeFontPadding="false"
android:paddingHorizontal="8dp"
android:paddingTop="3dp"
android:paddingBottom="3.75dp"
android:textColor="#color/white"
android:textSize="10sp"
app:layout_constraintBottom_toBottomOf="#+id/iv_item_outlet_buyer_photo"
app:layout_constraintEnd_toEndOf="parent"
tools:ignore="SmallSp"
tools:text="Open" />
<TextView
android:id="#+id/tv_item_outlet_buyer_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="10.5dp"
android:fontFamily="#font/notosansjp_bold"
android:includeFontPadding="false"
android:lineSpacingExtra="1.5dp"
android:paddingStart="15dp"
android:paddingEnd="#dimen/_17sdp"
android:paddingBottom="2dp"
android:textColor="#color/dark_gray"
android:textSize="#dimen/_10ssp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/iv_item_outlet_buyer_photo"
tools:text="Guttenburg, Alazka" />
<ImageView
android:id="#+id/iv_item_outlet_buyer_dotted_line"
android:layout_width="0dp"
android:layout_height="5dp"
android:layout_marginTop="5dp"
android:importantForAccessibility="no"
android:layerType="software"
android:paddingStart="16dp"
android:paddingEnd="15dp"
android:src="#drawable/dotted_shape"
app:layout_constraintEnd_toEndOf="#+id/tv_item_outlet_buyer_name"
app:layout_constraintStart_toStartOf="#+id/tv_item_outlet_buyer_name"
app:layout_constraintTop_toBottomOf="#+id/tv_item_outlet_buyer_name" />
<TextView
android:id="#+id/tv_item_outlet_buyer_category"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="4.5dp"
android:layout_marginBottom="14dp"
android:fontFamily="#font/notosansjp_regular"
android:includeFontPadding="false"
android:lineSpacingExtra="1.5dp"
android:paddingHorizontal="15dp"
android:textColor="#color/dark_gray"
android:textSize="11sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/iv_item_outlet_buyer_dotted_line"
tools:ignore="SmallSp"
tools:text="Food ∙ Drink ∙ Snack" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
I want make my GridLayout like this (edited in Figma):
But I got like this if last textView have constraintBottom_toBottomOf(parent):
And, I got like this if last textView not have constraintBottom_toBottomOf(parent):
What should I do?
You just need to make sure your TextView's layout_height is wrap_content, and give that the black background. The containing layout should be transparent, so when it resizes to fit the grid, the extra space is just "empty". The TextView shouldn't resize with it (and neither should anything else in the item's layout), so the black area stays the same - the extra height is unused.
Here's a quick example
MainFragment.kt
class MainFragment : Fragment(R.layout.fragment_main) {
lateinit var binding: FragmentMainBinding
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// fragment_main.xml has a RecyclerView in it with "recycler" for its ID
binding = FragmentMainBinding.bind(view)
with(binding) {
recycler.layoutManager = GridLayoutManager(requireContext(), 2)
recycler.adapter = Adapterino(requireContext())
}
}
private class Adapterino(val context: Context) : RecyclerView.Adapter<Adapterino.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder =
ItemViewBinding.inflate(LayoutInflater.from(context)).run(::ViewHolder)
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
// just generating random amounts of text to get some variation
holder.binding.textView.text =
generateSequence { "cats" }.take(Random.nextInt(5, 20)).joinToString(" ")
}
override fun getItemCount(): Int = 20
private class ViewHolder(val binding: ItemViewBinding) : RecyclerView.ViewHolder(binding.root)
}
}
item_view.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="8dp"
>
<View
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="#color/black"
/>
<ImageView
android:layout_width="match_parent"
android:layout_height="240dp"
android:src="#mipmap/ic_launcher"
/>
<TextView
android:id="#+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/black"
android:textColor="#color/white"
android:textSize="20sp"
/>
</LinearLayout>
Related
Im trying to make 2 recyclerview. And 2 of it using the same layout with Match Parent width. But the first Recyclerview display it properly but the second one doesnt.
My first Recyclerview 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="wrap_content"
android:background="#color/white"
android:gravity="center_vertical"
android:padding="10dp">
<ImageView
android:id="#+id/ivProduct"
android:layout_width="95dp"
android:layout_height="95dp"
android:scaleType="fitCenter"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription"
tools:src="#drawable/ic_image" />
<TextView
android:id="#+id/tvTitleProduct"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:fontFamily="#font/sen_bold"
android:textColor="#color/black"
android:textSize="15sp"
app:layout_constraintStart_toEndOf="#id/ivProduct"
app:layout_constraintTop_toTopOf="parent"
tools:text="Microsoft Office 2021 Pro Plus" />
<TextView
android:id="#+id/tvPriceProduct"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="11dp"
android:layout_marginTop="8dp"
android:fontFamily="#font/sen"
android:textColor="#color/black"
app:layout_constraintStart_toEndOf="#id/ivProduct"
app:layout_constraintTop_toBottomOf="#id/tvTitleProduct"
tools:text="Rp. 35.000,00" />
<com.google.android.material.button.MaterialButton
android:id="#+id/btnEditDisplayProduct"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginTop="8dp"
android:backgroundTint="#color/second_color"
android:fontFamily="sans-serif"
android:text="Edit"
android:textColor="#color/white"
android:textSize="12sp"
android:textStyle="bold"
app:cornerRadius="5dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="#id/ivProduct"
app:layout_constraintTop_toBottomOf="#id/tvPriceProduct"
tools:ignore="HardcodedText" />
<com.google.android.material.button.MaterialButton
android:id="#+id/btnPreviewDisplayProduct"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:backgroundTint="#color/second_color"
android:fontFamily="sans-serif"
android:text="Preview"
android:textColor="#color/white"
android:textSize="11sp"
android:textStyle="bold"
app:cornerRadius="5dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="#id/btnEditDisplayProduct"
app:layout_constraintTop_toBottomOf="#id/tvPriceProduct"
tools:ignore="HardcodedText" />
</androidx.constraintlayout.widget.ConstraintLayout>
And here is my second 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="wrap_content"
android:padding="10dp"
android:layout_marginTop="10dp"
android:background="#color/white">
<TextView
android:id="#+id/tvOwner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:fontFamily="#font/roboto"
android:textColor="#color/black"
android:textSize="14sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Buyyer\t: " />
<TextView
android:id="#+id/tvDevice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginTop="4dp"
android:fontFamily="#font/roboto"
android:textColor="#color/black"
android:textSize="14sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/tvOwner"
tools:text="Device\t: " />
<TextView
android:id="#+id/tvType"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginTop="4dp"
android:fontFamily="#font/roboto"
android:textColor="#color/black"
android:textSize="14sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/tvDevice"
tools:text="Tipe\t\t\t: " />
<TextView
app:layout_constraintHorizontal_weight="1"
android:id="#+id/tvToken"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginTop="4dp"
android:fontFamily="#font/roboto"
android:textColor="#color/black"
android:textSize="14sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/tvType"
tools:text="Token\t\t:" />
</androidx.constraintlayout.widget.ConstraintLayout>
And here is my oncreateviewholder code :
class ViewHolder(val binding : LicenseRecyclerviewAdapterBinding) :
RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent : ViewGroup, viewType : Int) : ViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val binding = LicenseRecyclerviewAdapterBinding.inflate(layoutInflater)
return ViewHolder(binding)
}
I tried to use dummyview but it still doesnt work
My fragment code :
override fun onViewCreated(view : View, savedInstanceState : Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentDaftarLisensiBinding.bind(view)
val listLicense = mutableListOf<License>()
val adapter = LicenseListAdapter(listLicense)
binding.rvLicense.adapter = adapter
binding.rvLicense.layoutManager = LinearLayoutManager(requireContext())
binding.rvLicense.setHasFixedSize(true)
viewModel.getLicenseData().observe(viewLifecycleOwner, Observer {
it.forEach { license ->
listLicense.add(license)
adapter.notifyItemInserted(listLicense.size - 1)
}
})
}
If you're talking about how the widths of the ViewHolders are wrong, this:
LicenseRecyclerviewAdapterBinding.inflate(layoutInflater)
needs to be this:
LicenseRecyclerviewAdapterBinding.inflate(layoutInflater, parent, false)
You need to pass the parent View in so it do stuff like work out what match_parent means in terms of size - it needs a parent to match to when you're inflating it! The false just means it doesn't actually attach it to the parent.
This is a pretty standard call when you're inflating layouts, like when you inflate a Fragment's view in onCreateView. It's pretty rare that you don't pass the parent/container so it can work out sizing and stuff!
I'm not sure how to ask this question. It seems easy to do but I'm not sure why it's not working. Anyways, here goes. I have this Error Banner that should be visible only if the total "Weight" for the Categories is less than or greater than 100. However my issue is that when the error banner is visible, my RecyclerView's last item is cut off, I think by the height of the error banner.
It will only be fixed if I edit it once again and the keyboard is shown, the recyclerview's height is refreshed (probably).
Here's my Layout XML:
<?xml version="1.0" encoding="utf-8"?>
<layout 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=".presentation.screens.gradesetup.gradingcategories.GradingCategoriesFragment">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/layoutParent"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.LinearLayoutCompat
android:id="#+id/layoutGradeCategoryList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintTop_toTopOf="parent"
app:layout_constrainedHeight="true" >
<TextView
android:id="#+id/tvInvalidGradeWeightLayout"
style="#style/Default_Text_Error_Banner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="#dimen/default_margin_size_16dp"
android:text="#string/error_invalid_grade_category_weight"
android:visibility="gone" />
<!-- Constraint layout_constraintHeight_max dynamically to 24% -->
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rvGradingCategories"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</androidx.appcompat.widget.LinearLayoutCompat>
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/tvInfoNoData"
style="#style/Default_Text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="#string/text_no_data_display"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.Barrier
android:id="#+id/barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="bottom"
app:constraint_referenced_ids="layoutGradeCategoryList" />
<androidx.appcompat.widget.LinearLayoutCompat
android:id="#+id/layout_adjust_weight"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="#dimen/default_margin_size_16dp"
android:orientation="horizontal"
app:layout_constraintBottom_toTopOf="#+id/buttonSave"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#+id/barrier"
app:layout_constraintVertical_bias="0.01">
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="#+id/switchViewAdjustWeight"
style="#style/Default_Text_Bold"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginEnd="#dimen/screen_padding_size"
android:text="#string/text_adjust_weight"
android:theme="#style/Theme.LMS"
android:visibility="gone" />
</androidx.appcompat.widget.LinearLayoutCompat>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="#dimen/default_margin_size_30dp"
android:src="#drawable/ic_plus"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:tint="#color/white" />
<androidx.appcompat.widget.AppCompatButton
android:id="#+id/buttonSave"
style="#style/Primary_Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="#dimen/default_margin_size_30dp"
android:enabled="false"
android:text="#string/text_save"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
As you can see I also have this Constraint Barrier, so whenever the height of the RecyclerView is longer, the SwitchMaterial("switchViewAdjustWeight") is also adjusted. I set the android:layout_constraintHeight_max dynamically based on device height.
// Dynamically set constraintMaxHeight
var constraintMaxHeight = 0
constraintMaxHeight =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val windowMetrics = activity!!.windowManager.currentWindowMetrics
val insets: Insets = windowMetrics.windowInsets
.getInsetsIgnoringVisibility(WindowInsets.Type.systemBars())
val height = windowMetrics.bounds.height() - insets.top - insets.bottom
(height * 0.7).toInt()
} else {
val displayMetrics = DisplayMetrics()
activity!!.windowManager.defaultDisplay.getMetrics(displayMetrics)
(displayMetrics.heightPixels * 0.7).toInt()
}
val constraintSet = ConstraintSet()
constraintSet.clone(layoutParent)
constraintSet.constrainMaxHeight(R.id.layoutGradeCategoryList, constraintMaxHeight)
constraintSet.applyTo(layoutParent)
In my code (kotlin): the error banner is toggled to visible if sum != 100
val result = sum == 100
binding.apply {
buttonSave.isEnabled = result
tvInvalidGradeWeightLayout.isVisible = !result
}
Target UI:
I also did change LinearLayout to ConstraintLayout However it didn't work, the Banner overlaps with the RecyclerView list :
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/layoutParent"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/layoutGradeCategoryList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintTop_toTopOf="parent"
app:layout_constrainedHeight="true" >
<TextView
android:id="#+id/tvInvalidGradeWeightLayout"
style="#style/Default_Text_Error_Banner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="#dimen/default_margin_size_16dp"
android:text="#string/error_invalid_grade_category_weight"
android:visibility="gone"
app:layout_constraintTop_toTopOf="parent"/>
<!-- Constraint layout_constraintHeight_max dynamically to 24% -->
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rvGradingCategories"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constrainedHeight="true"
app:layout_constraintTop_toBottomOf="#+id/tvInvalidGradeWeightLayout" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/tvInfoNoData"
style="#style/Default_Text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="#string/text_no_data_display"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.Barrier
android:id="#+id/barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="bottom"
app:constraint_referenced_ids="layoutGradeCategoryList" />
<androidx.appcompat.widget.LinearLayoutCompat
android:id="#+id/layout_adjust_weight"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="#dimen/default_margin_size_16dp"
android:orientation="horizontal"
app:layout_constraintBottom_toTopOf="#+id/buttonSave"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#+id/barrier"
app:layout_constraintVertical_bias="0.01">
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="#+id/switchViewAdjustWeight"
style="#style/Default_Text_Bold"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginEnd="#dimen/screen_padding_size"
android:text="#string/text_adjust_weight"
android:theme="#style/Theme.LMS"
android:visibility="gone" />
</androidx.appcompat.widget.LinearLayoutCompat>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="#dimen/default_margin_size_30dp"
android:src="#drawable/ic_plus"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:tint="#color/white" />
<androidx.appcompat.widget.AppCompatButton
android:id="#+id/buttonSave"
style="#style/Primary_Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="#dimen/default_margin_size_30dp"
android:enabled="false"
android:text="#string/text_save"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
This worked for me, I added getViewTreeObserver().addOnGlobalLayoutListener for layoutGradeCategoryList and trigger the request layout there.
layoutGradeCategoryList.getViewTreeObserver().addOnGlobalLayoutListener(OnGlobalLayoutListener {
layoutGradeCategoryList.requestLayout();
})
This helped me understand more on requestLayout/forceLayout/invalidate view.
https://stackoverflow.com/a/42430695/3777452
Hope this helps someone else.
I'm having a problem with my toolbar.
I want the device app and toolbar to be the same color, but don't use findviewbyid. (I'm migrating the entire project just to view binding
)
OK behavior (using findviewbyid).
NOK behavior (using view binding), is giving a little misalignment of the textView, it seems to receive a margin that was not placed.
But if I declare different in onWindowsInsetsChanged method or don't use it, I get another problem, the color is not correct.
Using findviewbyid:
override fun onWindowsInsetsChanged(view: View, insets: WindowInsets, padding: InitialPadding) {
with(binding) {
val toolbar = fragmentEditObjectiveNameRoot.findViewById<View>(R.id.toolbar)
toolbar.updatePadding(top = topInset)
editObjectiveNameRoot.updatePadding(
bottom = insets.systemWindowInsetBottom
)
}
}
Using view binding:
override fun onWindowsInsetsChanged(view: View, insets: WindowInsets, padding: InitialPadding) {
with(binding) {
//calling the include toolbar and the root of the toolbar fragment
toolbar.viewImageToolbar.updatePadding(
top = topInset
)
editObjectiveNameRoot.updatePadding(
bottom = insets.systemWindowInsetBottom
)
}
}
Different declaration in onWindowsInsetsChanged:
override fun onWindowsInsetsChanged(view: View, insets: WindowInsets, padding: InitialPadding) {
with(binding) {
//calling root from fragment and instead of calling the include toolbar and its root
fragmentEditObjectiveNameRoot.updatePadding(
top = topInset
)
editObjectiveNameRoot.updatePadding(
bottom = insets.systemWindowInsetBottom
)
}
}
I would like to leave the same color behavior when using findviewbyid, but with view binding, but without losing textView alignment.
Here is the xml that receives the toolbar include:
<?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"
android:id="#+id/fragmentEditObjectiveNameRoot"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/editObjectiveNameRoot"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:id="#+id/bgColorFrameLayout"
android:layout_width="match_parent"
android:layout_height="#dimen/color_frame_layout_height"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/toolbar" />
<androidx.core.widget.NestedScrollView
android:id="#+id/scrollView"
android:layout_width="0dp"
android:layout_height="0dp"
android:fillViewport="true"
android:clipToPadding="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/toolbar">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="#dimen/screen_margin_horizontal"
android:layout_marginTop="18dp"
android:layout_marginEnd="#dimen/screen_margin_horizontal"
android:paddingBottom="16dp">
<com.google.android.material.card.MaterialCardView
android:id="#+id/cardView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardBackgroundColor="#color/bari_white"
app:cardCornerRadius="#dimen/card_corner_radius"
app:cardElevation="0dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="#dimen/card_padding">
<TextView
android:id="#+id/titleSubAccount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="#string/sub_account_control_settings_edit_name"
android:textAlignment="center"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<br.com.bancobari.core_ui.views.text_input.BariTextInputLayout
android:id="#+id/nameInputLayout"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
app:helperIconEnabled="true"
app:helperStart_enabled="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/titleSubAccount">
<br.com.bancobari.core_ui.views.text_input.BariTextInputEditText
android:id="#+id/nameEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPersonName|textCapWords"
android:maxLength="16"
android:textAlignment="center"
android:textSize="16sp" />
</br.com.bancobari.core_ui.views.text_input.BariTextInputLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
<br.com.bancobari.core_ui.views.SubmitButton
android:id="#+id/saveButton"
style="#style/DefaultButton.Icon.Arrow"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="18dp"
android:text="#string/objective_settings_save"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/cardView"
app:layout_constraintVertical_bias="1.0" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
<include
android:id="#+id/toolbar"
layout="#layout/view_image_toolbar" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Here the toolbar 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="wrap_content">
<androidx.appcompat.widget.Toolbar
android:id="#+id/viewImageToolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:minHeight="#dimen/custom_toolbar_height"
app:contentInsetLeft="0dp"
app:contentInsetStart="0dp"
app:contentInsetStartWithNavigation="0dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<View
android:layout_width="0dp"
android:layout_height="#dimen/custom_toolbar_height" />
</androidx.appcompat.widget.Toolbar>
<TextView
android:id="#+id/iconEmojiView"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginEnd="10dp"
android:gravity="bottom"
android:textSize="22.5sp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="#id/toolbarTitleTextView"
app:layout_constraintEnd_toStartOf="#+id/toolbarTitleTextView"
tools:visibility="visible" />
<TextView
android:id="#+id/toolbarTitleTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:ellipsize="end"
android:fontFamily="#font/nunito_bold"
android:gravity="center"
android:lines="1"
android:textColor="#color/text_neutral_gray_800"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="#id/viewImageToolbar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Teste" />
<ImageView
android:id="#+id/toolbarRightIconImageView"
style="#style/Widget.AppCompat.ActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ic_settings"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="#id/toolbarTitleTextView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="#id/toolbarTitleTextView" />
</androidx.constraintlayout.widget.ConstraintLayout>
In your first block of code with findViewById, this
val toolbar = fragmentEditObjectiveNameRoot.findViewById<View>(R.id.toolbar)
returns the ConstraintLayout at the root of your included layout with the ID toolbar.
The property toolbar in your binding is another binding for the included layout rather than the root view of that layout. The root property of that included binding in this case is the same ConstraintLayout from above, so you should use instead:
toolbar.root.updatePadding(
top = topInset
)
What you were doing was changing the padding of an inner view of your complete Toolbar layout, the viewImageToolbar element.
I've noticed some RV performance issues.
I have a RecyclerView with some amount of items. When I launch my Fragment with RV and trying to scroll it for the first time I see some lags. I'll attach a GIF with active GPU profiling at the end of this question.
As you can see, I have a huge FPS drop when I start scrolling then it becomes smooth. So my question is -
Is it possible to optimise this process? I tried the following:
1. To create View for all my ViewHolders once:
private var itemView: View? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
if (itemView == null) {
itemView = LayoutInflater.from(parent.context).inflate(R.layout.rv_contact_item, parent, false)
}
return ContactViewHolder(itemView)
}
But it's not possible, cuz this view will be attached to it's parent with first onCreateViewHolder call and I'm getting crash "Detach your view from parent first".
2. Create ViewHolders in background thread.
Doesn't do anything too.
I know there's a possibility to create View programmatically, but will it work as intended? I have a pretty difficult View, so it would take some time to try it.
UPD:
My XML for single item:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:id="#+id/btn_contact"
android:orientation="horizontal"
android:padding="16dp"
android:background="?attr/selectableItemBackground">
<com.myapp.custom.AvatarView
android:id="#+id/v_avatar"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_marginEnd="16dp"
android:layout_gravity="center"
android:transitionName="chat_avatar_transition"
tools:background="#color/pale_red">
<com.myapp.custom.UserStatusView
android:id="#+id/v_user_status"
android:layout_width="18dp"
android:layout_height="18dp"
android:layout_gravity="bottom|end"/>
</com.myapp.custom.AvatarView>
<LinearLayout
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_gravity="center"
android:layout_marginEnd="10dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="#+id/iv_conference"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:baselineAlignBottom="true"
android:layout_marginEnd="2dp"
app:srcCompat="#drawable/ic_vector_conference"/>
<TextView
android:id="#+id/tv_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="16sp"
android:ellipsize="end"
android:lines="1"
android:transitionName="chat_name_transition"
tools:text="Title" />
</LinearLayout>
<TextView
android:id="#+id/tv_contact_subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#color/text_light"
android:textSize="14sp"
android:ellipsize="end"
android:lines="1"
tools:text="Subtitle" />
<LinearLayout
android:id="#+id/ll_last_message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="#+id/iv_message_direction"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginEnd="3dp"
app:srcCompat="#drawable/ic_vector_arrow_right" />
<TextView
android:id="#+id/tv_last_message"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textColor="#color/text_light"
android:textSize="14sp"
android:ellipsize="end"
android:lines="1"
tools:text="Hello!" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="#+id/iv_birthday"
android:layout_width="24dp"
android:layout_height="24dp"
app:srcCompat="#drawable/ic_vector_birthday" />
<ImageView
android:id="#+id/iv_app_type"
android:layout_width="24dp"
android:layout_height="24dp"
app:srcCompat="#drawable/ic_vector_mobile" />
<ImageView
android:id="#+id/iv_important_messages"
android:layout_width="24dp"
android:layout_height="24dp"
app:srcCompat="#drawable/ic_vector_flag" />
</LinearLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/iv_message_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:layout_gravity="bottom|end"
app:srcCompat="#drawable/ic_vector_checked" />
<TextView
android:id="#+id/tv_unread_counter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minHeight="24dp"
android:minWidth="24dp"
android:padding="3dp"
android:background="#drawable/shape_rect_rounded_12dp_blue_regular"
android:gravity="center"
android:textColor="#android:color/white"
android:layout_gravity="bottom|end"
tools:text="10" />
</FrameLayout>
</LinearLayout>
</LinearLayout>
UPD2:
My bind() method:
fun bind(contact: ContactModel) {
avatarView.apply {
initialize(
contact.id,
contact.avatar,
contact.fullName)
}
ivConference.visibility = if (ContactType.CONFERENCE == contact.type)
View.VISIBLE
else
View.GONE
tvName.text = contact.fullName
tvContactSubtitle.text = contact.subtitle
contact.lastMessageDirection?.let { direction ->
llLastMessage.visible
ivLastMessageDirection.setImageDrawable(
VectorDrawableCompat.create(
itemView.context.resources,
direction.icon,
null)
)
tvLastMessage.text = contact.lastMessage
} ?: llLastMessage.invisible
ivBirthday.visibility = if (contact.isBirthdayInc) {
View.VISIBLE
} else
View.GONE
ivImportantMessages.visibility = if (contact.hasImportantMessages)
View.VISIBLE
else
View.GONE
if (contact.unreadCounter == 0) {
tvUnreadCounter.gone
} else {
tvUnreadCounter.visible
tvUnreadCounter.text = contact.unreadCounter.toString()
}
}
That is because the quality of the image you've used is too high for so many item which takes time to optimize.
Please convert your images to WebP format for better performance.
Hope it helps.
I want to make a CardView recycler adapter to display 2 things(like first image).i have 2 xml layouts one with the toolbar and the other with the CardView.The problem is that the CardView is being displayed at the beginning of the screen and no toolbar is been displayed (only the arrow but still...).
This is what I get:
Here is my first xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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:id="#+id/constr"
android:layout_height="match_parent"
tools:context=".SettingsAct.SettingsActiv">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbarSettings"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="?attr/colorAccent"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarTheme"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/todayToolbarSettingsBtn"
android:layout_width="39dp"
android:layout_height="35dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:background="#drawable/ic_arrow_back_black_24dp"
app:layout_constraintEnd_toEndOf="#+id/toolbarSettings"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#+id/toolbarSettings" />
<TextView
android:id="#+id/settingsText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="230dp"
android:layout_marginTop="8dp"
android:text="#string/settingsText"
android:textColor="#color/colorWhite"
android:textSize="20sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="#+id/toolbarSettings" />
</android.support.constraint.ConstraintLayout>
Here is my second xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/name"
android:layout_width="match_parent"
android:layout_height="71dp"
android:layout_marginTop="8dp"
android:gravity="left"
android:paddingBottom="4dp"
android:paddingLeft="16dp"
android:text="TextView"
android:textColor="#000"
android:textSize="20sp"
android:textStyle="bold" />
<TextView
android:id="#+id/desc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginStart="20dp"
android:layout_marginTop="42dp"
android:gravity="bottom"
android:text="TextView"
android:textSize="18sp"
android:textStyle="bold" />
<View
android:layout_width="match_parent"
android:layout_height=".5dp"
android:background="#color/cardview_dark_background" />
</RelativeLayout>
</android.support.v7.widget.CardView>
And here is my main activity
class SettingsActiv : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_settings)
val constraintLayout = findViewById(R.id.constr) as ConstraintLayout
val recyclerView = RecyclerView(this)
val series = ArrayList<SeriesModel>()
series.add(SeriesModel("Unit of length","Meter"))
series.add(SeriesModel("Unit of temperature","Celcius"))
val adapter = MyAdapter(series)
recyclerView.setHasFixedSize(true)
recyclerView.layoutManager = LinearLayoutManager(this, LinearLayout.VERTICAL, false)
recyclerView.adapter = adapter
constraintLayout.addView(recyclerView)
}
}
Replace the constraint layout with a LinearLayout, set its orientation to vertical and use this code to add the recyclerview:
val linearLayout = findViewById(R.id.constr) as LinearLayout
recyclerView.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
linearLayout.addView(recyclerView, 1)
setSupportActionBar(findViewById(R.id.toolbarSettings))
supportActionBar?.setDisplayHomeAsUpEnabled(true)