I am trying to add a badge to the BottomNavigationView Item without using any library, however somehow the BottomNavigationView is not showing the badge (custom_view)
main_view.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/activity_main"
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"
tools:context="com.hrskrs.test.MainActivity">
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.design.widget.BottomNavigationView
android:id="#+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
app:itemBackground="#color/colorPrimary"
app:itemIconTint="#color/colorAccent"
app:itemTextColor="#color/colorPrimaryDark"
app:menu="#menu/bottom_navigation_main" />
</RelativeLayout>
bottom_navigation_menu.xml:
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/item_test"
android:icon="#mipmap/ic_launcher"
android:title="action1"
app:showAsAction="always" />
<item
android:enabled="true"
android:icon="#mipmap/ic_launcher"
android:title="action2"
app:showAsAction="ifRoom" />
<item
android:enabled="true"
android:icon="#mipmap/ic_launcher"
android:title="action3"
app:showAsAction="ifRoom" />
</menu>
Activity extended from AppCompatActivity:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
menu = bottomNavigationView.getMenu();
menu.clear();
getMenuInflater().inflate(R.menu.bottom_navigation_main, menu);
MenuItem item = menu.findItem(R.id.item_test);
item = MenuItemCompat.setActionView(item, R.layout.custom_view);
RelativeLayout badgeWrapper = (RelativeLayout) MenuItemCompat.getActionView(item);
TextView textView = (TextView) badgeWrapper.findViewById(R.id.txtCount);
textView.setText("99+");
return super.onCreateOptionsMenu(menu);
}
custom_view.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
style="#android:style/Widget.ActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#android:color/transparent"
android:clickable="true"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="Notification Icon"
android:gravity="center"
android:src="#mipmap/ic_launcher" />
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/txtCount"
android:gravity="right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/ic_badge"
android:text="55"
android:textColor="#ffffffff"
android:textSize="12sp" />
</RelativeLayout>
Istead of showing (badge) custom_view it shows the item itself only:
Below you can see from the debug mode that the view accessed is the right one and it is being set correctly. However somehow the BottomNavigationViewis not being invalidated:
You can use the BottomNavigationView provided by the Material Components Library.
Just add the BottomNavigationView to your layout:
<com.google.android.material.bottomnavigation.BottomNavigationView
android:layout_gravity="bottom"
app:menu="#menu/navigation_main"
../>
Then use in your code:
int menuItemId = bottomNavigationView.getMenu().getItem(0).getItemId();
BadgeDrawable badge = bottomNavigationView.getOrCreateBadge(menuItemId);
badge.setNumber(2);
To change the badge gravity use the setBadgeGravity method.
badge.setBadgeGravity(BadgeDrawable.BOTTOM_END);
I managed to make BottomNavigationView with the badge. Here is my code (Kotlin).
This is the panel (inherited from BottomNavigationView)
/** Bottom menu with badge */
class AdvancedBottomNavigationView(context: Context, attrs: AttributeSet) : BottomNavigationView(context, attrs) {
private companion object {
const val BADGE_MIN_WIDTH = 16 // [dp]
const val BADGE_MARGIN_TOP = 5 // [dp]
const val BADGE_MARGIN_LEFT = 15 // [dp]
}
#Inject internal lateinit var uiCalculator: UICalculatorInterface
private val bottomMenuView: BottomNavigationMenuView
init {
// Get access to internal menu
val field = BottomNavigationView::class.java.getDeclaredField("mMenuView")
field.isAccessible = true
bottomMenuView = field.get(this) as BottomNavigationMenuView
App.injections.presentationLayerComponent!!.inject(this)
#SuppressLint("CustomViewStyleable")
val a = context.obtainStyledAttributes(attrs, R.styleable.advanced_bottom_navigation_bar)
val badgeLayoutId = a.getResourceId(R.styleable.advanced_bottom_navigation_bar_badge_layout, -1)
a.recycle()
initBadges(badgeLayoutId)
}
/**
* [position] index of menu item */
fun setBadgeValue(position: Int, count: Int) {
val menuView = bottomMenuView
val menuItem = menuView.getChildAt(position) as BottomNavigationItemView
val badge = menuItem.findViewById(R.id.bottom_bar_badge)
val badgeText = menuItem.findViewById(R.id.bottom_bar_badge_text) as TextView
if (count > 0) {
badgeText.text = count.toString()
badge.visibility = View.VISIBLE
} else {
badge.visibility = View.GONE
}
}
/**
* Select menu item
* [position] index of menu item to select
*/
fun setSelected(position: Int) = bottomMenuView.getChildAt(position).performClick()
private fun initBadges(badgeLayoutId: Int) {
// Adding badges to each Item
val menuView = bottomMenuView
val totalItems = menuView.childCount
val oneItemAreaWidth = uiCalculator.getScreenSize(context).first / totalItems
val marginTop = uiCalculator.dpToPixels(context, BADGE_MARGIN_TOP)
val marginLeft = uiCalculator.dpToPixels(context, BADGE_MARGIN_LEFT)
for (i in 0 until totalItems) {
val menuItem = menuView.getChildAt(i) as BottomNavigationItemView
// Add badge to every item
val badge = View.inflate(context, badgeLayoutId, null) as FrameLayout
badge.visibility = View.GONE
badge.minimumWidth = uiCalculator.dpToPixels(context, BADGE_MIN_WIDTH)
val layoutParam = FrameLayout.LayoutParams(
FrameLayout.LayoutParams.WRAP_CONTENT,
FrameLayout.LayoutParams.WRAP_CONTENT)
layoutParam.gravity = Gravity.START
layoutParam.setMargins(oneItemAreaWidth / 2 + marginLeft, marginTop, 0, 0)
menuItem.addView(badge, layoutParam)
}
}
}
It's attr.xml file with options for this component:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="advanced_bottom_navigation_bar">
<attr name="badge_layout" format="reference|integer" />
</declare-styleable>
</resources>
Background for badge from drawable folder:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<solid android:color="#ff0000" />
<corners android:radius="10dp" />
</shape>
</item>
</selector>
Badge itself:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
android:id="#+id/bottom_bar_badge"
android:layout_height="20dp"
android:layout_width="20dp"
xmlns:android="http://schemas.android.com/apk/res/android"
android:background="#drawable/bcg_badge"
>
<TextView
android:id="#+id/bottom_bar_badge_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="1"
android:textSize="10sp"
android:textColor="#android:color/white"
xmlns:android="http://schemas.android.com/apk/res/android"
android:textAlignment="center"
android:layout_gravity="center"/>
</FrameLayout>
And this is an example how to use it in your code:
<?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:layout_height="match_parent"
tools:context="su.ivcs.ucim.presentationLayer.userStories.mainScreen.view.MainActivity">
<su.ivcs.ucim.presentationLayer.common.advancedBottomNavigationView.AdvancedBottomNavigationView
android:id="#+id/bottom_navigation"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
app:itemBackground="#android:color/white"
app:itemIconTint="#color/main_screen_tabs_menu_items"
app:itemTextColor="#color/main_screen_tabs_menu_items"
app:menu="#menu/main_screen_tabs_menu"
app:badge_layout = "#layout/common_badge"
app:layout_constraintTop_toBottomOf="#+id/fragmentsContainer"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>
</android.support.constraint.ConstraintLayout>
I hope this helps you.
#hrskrs Try adding a higher elevation on your txtCount or badgeWrapper itself.
BottomNavigationView seems to have higher elevation than the views on the screen.
I struggled with showing badges on BottomNavigationView items. My badge (without any text value) being part of the drawable itself turned grey when user clicked other item or became the same color defined in the tint (if not defined is colorPrimary).
I think you will run into the same problem I faced with colouring of the badge/counter on top of menu item of BottomNavigationViewas tint color will be applied to the item itself and your badgeWrapper being part of MenuItem will take the tint (turns grey when you tap any other item which you will not want I guess).
Check out my answer here: Is there a way to display notification badge on Google's official BottomNavigationView menu items introduced in API 25?
I used an ImageView for a badge but you can have your badgeWrapper RelativeView instead of the ImageView.
use the BadgeDrawable like this:
Integer amount = tabBadgeCountMap.get(tab);
BadgeDrawable badgeDrawable = bottomNavigationView.getOrCreateBadge(tabMenuResId);
badgeDrawable.setNumber(amount != null ? amount : 0);
Related
I want to animate TabLayout dot indicator to stretch it on selected state. I used default animation to do that but its bugged and it cant take default shape by animating width only. After animation its stretched to rectangle and I don't understand why.
Code:
val vg = tabLayout.getChildAt(0) as ViewGroup
tabLayout.addOnTabSelectedListener(object: TabLayout.ViewPagerOnTabSelectedListener(viewPager){
override fun onTabReselected(tab: TabLayout.Tab) {}
override fun onTabUnselected(tab: TabLayout.Tab) {
val tabDot = vg.getChildAt(tab.position)
tabDot?.let { v->
animateDotWidthDefault(v)
animateDotColor(v, R.color.selected_blue, R.color.default_grey)
}
}
override fun onTabSelected(tab: TabLayout.Tab) {
val tabDot = vg.getChildAt(tab.position)
tabDot?.let { v->
animateDotWidthStretch(v)
animateDotColor(v, R.color.default_grey, R.color.selected_blue)
}
}
})
private fun animateDotWidthDefault(tabDot: View){
val widthAnimator = ValueAnimator.ofInt(stretchedWidth, defaultWidth)
widthAnimator.duration = 500
widthAnimator.interpolator = DecelerateInterpolator()
widthAnimator.addUpdateListener { animation ->
tabDot.layoutParams.width = animation.animatedValue as Int
tabDot.requestLayout()
}
widthAnimator.start()
}
private fun animateDotWidthStretch(tabDot: View){
val widthAnimator = ValueAnimator.ofInt(defaultWidth, stretchedWidth)
widthAnimator.duration = 500
widthAnimator.interpolator = AccelerateInterpolator()
widthAnimator.apply {
addUpdateListener { animation ->
tabDot.layoutParams.width = animation.animatedValue as Int
tabDot.requestLayout()
}
}
widthAnimator.start()
}
TabIndicator:
<?xml version="1.0" encoding="utf-8"?>
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<item android:gravity="center">
<shape
android:shape="oval"
android:useLevel="false">
<solid android:color="#color/selected_blue" />
<size
android:width="8dp"
android:height="8dp"/>
</shape>
</item>
</layer-list>
Goal:
Reality:
The bug could definitely be related to the
android:fillAfter="true"
android:fillEnabled="true"
configurations on the XML. Could you paste the original XML and the container so we can edit our answer and give a more accurate solution to your issue.
Great component by the way, I tested it on my end and it works perfect with this XML config:
<!-- For demonstration / testing purposes -->
<com.google.android.material.tabs.TabLayout
android:id="#+id/indicator3"
android:layout_width="wrap_content"
android:layout_height="36dp"
android:layout_alignParentBottom="true"
android:layout_marginStart="14dp"
android:layout_marginBottom="64dp"
android:clipChildren="false"
android:clipToPadding="false"
app:tabBackground="#drawable/tablayout_unselected"
app:tabGravity="center"
app:tabIndicator="#drawable/tablayout_selected2"
app:tabIndicatorAnimationDuration="250"
app:tabIndicatorAnimationMode="elastic"
app:tabIndicatorColor="#color/xxxRed"
app:tabIndicatorFullWidth="false"
app:tabIndicatorGravity="bottom"
app:tabIndicatorHeight="6dp"
app:tabMode="scrollable"
android:fillAfter="true"
android:fillEnabled="true"
app:tabRippleColor="#color/carbon_red_a700"
app:tabSelectedTextColor="#color/black"
app:tabTextColor="#android:color/black"
app:tabUnboundedRipple="true">
<com.google.android.material.tabs.TabItem
android:id="#+id/firstTab"
android:layout_width="12dp"
android:layout_height="wrap_content" />
<com.google.android.material.tabs.TabItem
android:id="#+id/secondTab"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<com.google.android.material.tabs.TabItem
android:id="#+id/thirdTab"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<com.google.android.material.tabs.TabItem
android:id="#+id/fourthTab"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<com.google.android.material.tabs.TabItem
android:id="#+id/fifthTab"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</com.google.android.material.tabs.TabLayout>
edit1:
I just figured out that even though you didn't provide the animateDotColor() function, ChatGPT took a guess and provided this missing function.
It turns out it is exactly this function that's causing the trouble for you, removing the rounded corners.
private fun animateDotColor(tabDot: View, fromColor: Int, toColor: Int) {
val colorAnimator = ValueAnimator.ofObject(
ArgbEvaluator(),
ContextCompat.getColor(tabDot.context, fromColor),
ContextCompat.getColor(tabDot.context, toColor)
)
colorAnimator.duration = 500
colorAnimator.interpolator = DecelerateInterpolator()
colorAnimator.addUpdateListener { animation ->
tabDot.setBackgroundColor(animation.animatedValue as Int)
}
colorAnimator.start()
}
Because it's replacing the background of the TabItem().
Solution is instead of setting the color, setting the same background with a different color, so you can preserve the edges and corners. I am going through the same work right now and I will edit a second time and provide you this code as well.
edit2:
Here's the working animateDotColor function for you, this one doesn't remove the corners. Enjoy it buddy.
private fun animateDotColor2(tab: TabView, color: Int) {
tab.background = AppCompatResources.getDrawable(tab.context, R.drawable.tablayout_selected_final)
}
I want to keep the background changed like a disco screen.
But in this code, the only blue color is shown. What should I fix to change color kept changed?
var bgColor = 1
val bgDrawableIds = intArrayOf(
R.drawable.purple,
R.drawable.red,
R.drawable.blue,
)
bgColor++
disco_display.background = resources.getDrawable(bgDrawableIds[bgColor % bgDrawableIds.size])
xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/disco_display"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/white" />
</androidx.constraintlayout.widget.ConstraintLayout>
Wrap it in a coroutine:
lifecycleScope.launch {
while (true) {
disco_display.background = resources.getDrawable(bgDrawableIds[++bgColor % bgDrawableIds.size])
delay(200L)
}
}
i want to know what is wrong with my code as there is no any responding to my clicks on the menu item
class Main : AppCompatActivity() , NavigationView.OnNavigationItemSelectedListener {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(mainToolbar)
supportActionBar?.title = ""
val toolbarToggle = ActionBarDrawerToggle(this,DrawerLayout,mainToolbar,R.string.drawer_open,R.string.drawer_close)
DrawerLayout.addDrawerListener(toolbarToggle)
toolbarToggle.syncState()
mainNavigView.setNavigationItemSelectedListener(this)
}
override fun onNavigationItemSelected(item: MenuItem): Boolean {
var titleT = item.title
Toast.makeText(this,titleT, Toast.LENGTH_LONG).show()
return true
}
}
this is xml code for navigation and drawer
<androidx.drawerlayout.widget.DrawerLayout
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/DrawerLayout"
android:background="#color/spark_bg"
tools:context=".Main">
<com.google.android.material.navigation.NavigationView
android:id="#+id/mainNavigView"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="#layout/navigationheader"
app:menu="#menu/navigationmenu"
/>
this is menu item code that contains id for the item i wanted to press
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/myOrdersMI"
android:icon="#drawable/ic_list"
android:title="My Orders"
/>
</menu>
To use a DrawerLayout, position your primary content view as the first child with width and height of match_parent and no <layout_gravity>
<androidx.drawerlayout.widget.DrawerLayout
...>
<!-- main content goes here -->
<!-- NavigationView -->
<com.google.android.material.navigation.NavigationView
android:layout_gravity="start|left"
../>
</androidx.drawerlayout.widget.DrawerLayout>
In my current project I have a RecyclerView with a rounded rectangle as its border. I set it using the background view tag in my layout xml and it produces the correct effect:
<androidx.recyclerview.widget.RecyclerView
...
android:background="#drawable/layout_sample_view_background"
....
/>
The problem arises when I longclick() one of the view items and open a floating action mode menu using ActionMode.Callback2. This selection overlaps the borders of my RecyclerView:
Btw. Not sure this is important, but the viewitems inside my RecyclerView/ListAdapter are using a custom view:
/**
* Custom view for each [RecyclerView] list item in the list inside a [SampleView]
*/
class SampleListItem(context: Context, attrs: AttributeSet, #AttrRes defStyleAttr: Int) : ConstraintLayout(context, attrs, defStyleAttr), View.OnLongClickListener {
constructor(context: Context, attrs: AttributeSet) : this(context, attrs, 0)
init {
setOnLongClickListener(this)
clipToOutline = false
}
private val binding: LayoutSampleListItemBinding = LayoutSampleListItemBinding.inflate(LayoutInflater.from(context), this)
var sample: Sample? = null
set(value) {
field = value
fun Long.toTimeString(): String {
val date = ZonedDateTime.ofInstant(Instant.ofEpochMilli(this), ZoneId.systemDefault())
val formatter = DateTimeFormatter.ofPattern("HH:mm")
val time = date.format(formatter)
Timber.d("With $this time was: $time")
return time
}
checkNotNull(value)
binding.id.text = value.sampleNumber.toString()
binding.timestamp.text = value.sampleTime.toTimeString()
binding.comment.text = SpannableStringBuilder(value.comment)
}
private var sampleItemClickListener = object : SampleItemClickListener {
override fun onSampleEditClick(sample: Sample) {
Timber.d("ActionMode edit icon clicked. Please edit $sample")
isSelected = !isSelected
}
override fun onSampleDeleteClick(sample: Sample) {
Timber.d("ActionMode delete icon clicked. Please delete $sample")
isSelected = !isSelected
}
}
interface SampleItemClickListener {
fun onSampleEditClick(sample: Sample)
fun onSampleDeleteClick(sample: Sample)
}
override fun onLongClick(v: View?): Boolean {
Toast.makeText(context,"longClick $sample", Toast.LENGTH_LONG).show()
// Start floating ActionMode
isSelected = true
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val floatingActionModeCallback = SampleViewItemActionModeCallback(this, sampleItemClickListener, R.menu.sampleviewitem_menu_actions)
}
return true
}
}
I set the ripple effect of this custom view using the following drawable:
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#color/colorPrimaryLight">
<item
android:id="#android:id/mask"
android:drawable="#color/icon_inactive_light_background" />
<item>
<selector>
<item android:state_selected="true">
<color android:color="#color/colorPrimaryLight"/>
</item>
<item android:state_activated="true">
<color android:color="#color/colorPrimaryLight"/>
</item>
<item>
<color android:color="#android:color/transparent"/>
</item>
</selector>
</item>
</ripple>
The layout of the custom view:
<?xml version="1.0" encoding="utf-8"?>
<merge
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"
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
<com.google.android.material.textview.MaterialTextView
android:id="#+id/id"
style="#style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textAlignment="center"
app:layout_constraintEnd_toStartOf="#+id/timestamp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#+id/comment"
app:layout_constraintWidth_percent="0.10"
tools:text="#sample/samples.json/data/sampleId" />
<com.google.android.material.textview.MaterialTextView
android:id="#+id/timestamp"
style="#style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textAlignment="center"
app:layout_constraintEnd_toStartOf="#+id/comment"
app:layout_constraintStart_toEndOf="#+id/id"
app:layout_constraintTop_toTopOf="#+id/comment"
app:layout_constraintWidth_percent="0.20"
tools:text="#sample/samples.json/data/timestamp" />
<com.google.android.material.textview.MaterialTextView
android:id="#+id/comment"
style="#style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#id/sampleviewitem_optional_icon"
app:layout_constraintStart_toEndOf="#id/timestamp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_percent="0.60"
tools:hint="Kommentar"
tools:text="#sample/samples.json/data/comment" />
<com.google.android.material.button.MaterialButton
android:id="#+id/sampleviewitem_optional_icon"
style="#style/IconOnlyButton"
android:layout_width="0dp"
android:layout_height="0dp"
app:icon="#drawable/ic_edit_white_24dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="#+id/layout_sample_item_sample_comment"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintWidth_percent="0.10" />
</merge>
Does anyone know what causes this effect and how to avoid this behavior? I know of ViewOutlineProvider, but I'm just not familiar with it. Could it maybe solve this issue?
For others that might come across this problem. The solution to this was to wrap the RecyclerView in a MaterialCardView (a regular CardView could also work).
Like this:
<com.google.android.material.card.MaterialCardView
android:id="#+id/sample_container"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
app:cardElevation="0dp"
app:cardCornerRadius="4dp"
app:strokeColor="#color/icon_active_unfocused_light_background"
app:strokeWidth="1dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#id/layout_sample_view_icon"
app:layout_constraintTop_toTopOf="#id/layout_sample_view_icon"
>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/layout_sample_view_recyclerview"
android:layout_height="match_parent"
android:layout_width="match_parent"
tools:itemCount="4"
tools:listitem="#layout/layout_patientsample_listitem"
/>
</com.google.android.material.card.MaterialCardView>
Here's a screenshot of the outcome:
Use padding in your RecyclerView
<androidx.recyclerview.widget.RecyclerView
...
android:background="#drawable/layout_sample_view_background"
android:padding="5dp"
....
/>
I use Android Studio with Kotlin and I have a problem with my Toolbar, when I create it, it hides my others elements on my activity =>
Without Toolbar
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main))
val user = User("Bob", 20)
findViewById<Button>(R.id.go_to_second).setOnClickListener {
println("Lancement de la seconde activité")
val intent = Intent(this, Second::class.java)
intent.putExtra("user", user)
startActivity(intent)
}
findViewById<Button>(R.id.bouton_dialogue).setOnClickListener {
val confdial = ConfirmDialog()
confdial.listener = object: ConfirmDialog.ConfDeleteListener {
override fun onPositiveClick() {
Log.i("MainActivity", "Recuperation du postive suppression dialog")
val dd = FileListDialog()
dd.show(supportFragmentManager, "onPositiveClick")
}
override fun onNegativeClick() {
Log.i("MainActivity", "Confirmation du negative suppression dialog")
}
}
confdial.show(supportFragmentManager, "confirmDelete")
}
}
}
activity_main.xml :
<?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="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:layout_gravity="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:visibility="visible"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/go_to_second"
android:visibility="visible"
android:layout_gravity="center"
android:text="go pr l'aventure" />
<Button
android:id="#+id/bouton_dialogue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="visible"
android:text="lancement dialogue" />
Result =>
result without toolbar
With Toolbar
MainActivity.kt
import android.content.Intent
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.support.v7.widget.Toolbar
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.widget.Button
import android.widget.Toast
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val toolbar = findViewById<Toolbar>(R.id.toolbar)
setSupportActionBar(toolbar)
val user = User("Bob", 20)
findViewById<Button>(R.id.go_to_second).setOnClickListener {
println("Lancement de la seconde activité")
val intent = Intent(this, Second::class.java)
intent.putExtra("user", user)
startActivity(intent)
}
findViewById<Button>(R.id.bouton_dialogue).setOnClickListener {
val confdial = ConfirmDialog()
confdial.listener = object: ConfirmDialog.ConfDeleteListener {
override fun onPositiveClick() {
Log.i("MainActivity", "Recuperation du postive suppression dialog")
val dd = FileListDialog()
dd.show(supportFragmentManager, "onPositiveClick")
}
override fun onNegativeClick() {
Log.i("MainActivity", "Confirmation du negative suppression dialog")
}
}
confdial.show(supportFragmentManager, "confirmDelete")
}
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.main_menu, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
when(item?.itemId){
R.id.action_second -> {
val intent = Intent(this, Menu_activiy::class.java)
startActivity(intent)
return true
}
R.id.action_delete -> {
Toast.makeText(this, "supprimer", Toast.LENGTH_LONG).show()
return true
}
else -> return super.onOptionsItemSelected(item)
}
}
}
activity_main.xml
<?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="match_parent"
tools:context=".MainActivity">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_height="?attr/actionBarSize"
android:layout_width="match_parent"
android:background="#color/colorPrimary"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:layout_gravity="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:visibility="visible"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/go_to_second"
android:visibility="visible"
android:layout_gravity="center"
android:text="go pr l'aventure" />
<Button
android:id="#+id/bouton_dialogue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="visible"
android:text="lancement dialogue" />
</LinearLayout>
main_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="#+id/action_second"
android:icon="#mipmap/ic_launcher_round"
android:title="Seconde"
app:showAsAction="always"/>
<item android:id="#+id/action_save"
android:icon="#drawable/epee"
android:title="Enregistrer"
app:showAsAction="always"/>
<item android:id="#+id/action_delete"
android:icon="#drawable/pioche"
android:title="Supprimer"
app:showAsAction="ifRoom"/>
<item android:id="#+id/action_help"
android:icon="#drawable/pomme"
android:title="Aide"
app:showAsAction="never"/>
</menu>
Result with ToolBar =>
Result with ToolBar
So we can see ToolBar but others elements like "Hello World" TextView has disappeared
Set the orientation of the LinearLayout:
android:orientation="horizontal" or android:orientation="vertical" also delete all the attributes that refer to ConstraintLayout.
Your toolbar's width is match_parent. This mean toolbar width is same your parent view. Your other views are still there but they are not visible, because LinearLayout's orientation is horizontal. They are out of parent view (LinearLayout).
You must change your parent layouts orientation to vertical or change your parent views type.
I guess the problem is the same which is stated in the above answer.
When the orientation of a LinearLayout is unspecified, it is using the default, which is horizontal. Should the layout be a column or a row? Use "horizontal" for a row, "vertical" for a column. The default is horizontal.
Since you are not giving any orientation it's horizontal and pushing other views out of scope so you better give a orientation in your linear layout.
android:orientation="vertical"
you can margin your hello world textView with
android:layout_marginTop="?attr/actionBarSize"