How to remove AppBar shadow after app start - android

I have drawer layout, where I need to remove AppBar shadow for particular page (fragment).
For this I am using this code
fun setToolbarShadow(dropShadow: Boolean) {
if (dropShadow) {
ViewCompat.setElevation(appBar, Utils.dp2px(4, resources))
} else {
ViewCompat.setElevation(appBar, 0f)
}
}
and it works well for others than the first fragment.
I tried put it inside onCreate of activity, onStart, onCreateView and onViewCreated of fragment, but nothing works.
How to set it properly after activity and fragment are created?
EDIT:
I made simple hello world app with one activity to try it, here is the code:
activity_main.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:layout_height="match_parent"
tools:context="cz.svobodaf.myapplication.MainActivity">
<android.support.design.widget.AppBarLayout
android:id="#+id/appBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/ThemeOverlay.AppCompat.ActionBar"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:theme="#style/ThemeOverlay.AppCompat.ActionBar"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"/>
<FrameLayout
android:id="#+id/top_nav_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
</android.support.design.widget.AppBarLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
ViewCompat.setElevation(appBar, 0f)
}
override fun onResume() {
super.onResume()
ViewCompat.setElevation(appBar, 0f)
}
}
This also doesn't work after start, but when I lock device and unlock again, onResume is called and suddenly it works.
I need to know ehere to put the code to set elevation after app start.

I found solution by setting AppBar outlines to null.
appBar.outlineProvider = null
But I couldn't figure out why elevation doesn't work. It looks like elevation is set after all starting methods are called -.-

Related

Fragment not using full height of screen, but only after coming back from another Activity

I have an Activity with a TabLayout, a ViewPager2 and a FragmentContainerView like this:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:theme="#style/AppTheme"
tools:context="com.safirecctv.easyview.activities.main.MainActivity">
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true">
<com.google.android.material.appbar.MaterialToolbar
android:id="#+id/activity_main_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#color/visiotech_red"
app:popupTheme="#style/AppTheme" />
<com.google.android.material.tabs.TabLayout
android:id="#+id/activity_main_tab_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/visiotech_red"
app:tabIconTint="?attr/tabLayoutTabColor"
app:tabIndicatorColor="?attr/colorSecondary" />
<androidx.viewpager2.widget.ViewPager2
android:id="#+id/activity_main_view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.fragment.app.FragmentContainerView
android:id="#+id/main_fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/app_bar" />
</RelativeLayout>
When I first launch the Activity with its Fragment (I've reduced it to one tab and one fragment for the sake of simplicity), everything works as expected, the Fragment takes the whole screen. But when I come back from another Activity by calling:
mActivity?.finish()
The fragment loads well, but only takes half of the screen height. I've tried to inspect with Layout Inspector, but if I attach it before coming back, the app force closes, and if I attach it after (when the Fragment is loaded and only taking half of the screen height), then it recreates and works well again.
I am testing in a real device, not in the emulator.
This is my Fragment XML:
<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">
<data>
<variable name="viewModel" type="com.safirecctv.easyview.viewmodels.main.DeviceManagementViewModel"/>
</data>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:orientation="vertical"
android:id="#+id/list_view_devices"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/listViewBackgroundColor"
app:data="#{viewModel.devices}" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:layout_margin="16dp"
android:src="#drawable/icon_plus"
app:backgroundTint="#color/visiotech_red"
app:tint="?attr/buttonTextColor"
tools:ignore="ContentDescription" />
</RelativeLayout>
</layout>
And this is the code behind:
package com.safirecctv.easyview.activities.add_edit_device.fragments
import android.os.Bundle
import android.view.View
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import com.safirecctv.easyview.R
import com.safirecctv.easyview.databinding.ActivityAddEditDeviceIpddnsFragmentBinding
import com.safirecctv.easyview.viewmodels.add_edit_device.IpDdnsDeviceViewModel
import dagger.hilt.android.AndroidEntryPoint
/**
* Fragment used to add or edit IP/DDNS devices to/from the database.
* As of June, 2021, the following vendors support IP/DDNS login: Safire/Hikvision, XSecurity/Dahua, Uniview.
*/
#AndroidEntryPoint
class AddEditIPDDNSDeviceFragment : Fragment(R.layout.activity_add_edit_device_ipddns_fragment) {
private val mViewModel: IpDdnsDeviceViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val binding = ActivityAddEditDeviceIpddnsFragmentBinding.bind(view)
binding.apply {
btnSaveDeviceIpDdns.setOnClickListener { trySaveDevice() }
viewModel = mViewModel
lifecycleOwner = viewLifecycleOwner
}
}
//endregion
//region Device methods
private fun trySaveDevice() {
//mViewModel.trySaveDevice()
activity?.finish()
}
//endregion
}
Could it be related to the fact that I'm not calling onCreateView in the Fragment but instead delegating it to the constructor?
Thank you very much.
EDIT: I could open Layout Inspector finally, and this is what it shows: RecyclerViewImpl is taking the whole space but the FrameLayout inside it only takes like half of the screen:
I finally found it. The problem was in the Activity's XML. Everything was inside AppBarLayout and that was causing the issue. I just left the MaterialToolbar inside AppBarLayout and the rest as a sibling, as explained in this post (in Spanish). Then everything started working as intended.

OnClick not called while I get OnTouch event

I have an issue on my app I am trying to solve it from 2 days now but I can't find anything about it.
Almost every single button in a fragment which is added dynamically at my Activity onCreate are not clickable for some users. Nobody in my team experiences the issue so, I reached a user with the bug and made some test with him and here are the results:
If he clicks just once the button doesn't work but if he spams it, the button sometimes trigger.
I have also placed some debugging in his version and this is what I found:
user_hud_main_button.setOnTouchListener { v, event ->
when (event.action) {
MotionEvent.ACTION_DOWN -> report += "down;"
MotionEvent.ACTION_UP -> report += "up;"
}
false
}
user_hud_main_button.setOnClickListener {
report += "click;"
toggleMainButton()
Analytics.send(Event.Type.BtnAddMain)
}
edit: the setOnTouchListener has been added only for debug purpose while working on the problem
while on my test phones I get:
down;up;click;down;up;click;down;up;click;
the user get:
down;up;down;up;down;up;down;up;
The up and down events are correctly sent but not the onclick. Why does this happen and why only for few users ?
Here is the layout of the activity:
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:name="com.hulab.mapstr.newArch.MapFragment"
android:id="#+id/activity_map_fragment_map"
android:layout_width="match_parent"
android:layout_height="match_parent" />
...
<FrameLayout
android:id="#+id/activity_map_hud_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
<!-- Bottom drawer -->
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="#layout/main_bottom_sheet"></include>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
activity code:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
...
supportFragmentManager.beginTransaction().add(R.id.activity_map_hud_container, UserHUDFragment()).commit()
...
}
UserHUDFragment:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
...
user_hud_main_button.setOnClickListener {
toggleMainButton()
Analytics.send(Event.Type.BtnAddMain)
}
...
}
UserHUD layout:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/user_hud">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/user_hud_current_map_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/user_hud_main_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:elevation="1dp"
app:fabSize="normal"
app:useCompatPadding="true"
android:src="#drawable/add_fab_button" />
...
</androidx.constraintlayout.widget.ConstraintLayout>
...
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>
Thanks in advance and sorry for my english
It is not allowed to have both onTouch and onClick listener on one view. You can do everything with onTouchListener.
Ok the problem was that I had a "infinite loop" from my activity asking for a permission when users declined it with "don't ask again" option, so every click event was broken

setSupportActionBar and toolbar.inflateMenu don't work together?

Calling setSupportActionBar and inflating a menu as follows results in not showing the menu:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(myToolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
myToolbar.inflateMenu(R.menu.my_menu)
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.appcompat.widget.Toolbar
android:id="#+id/myToolbar"
android:layout_width="0dp"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<?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/test"
android:title="Test"
app:showAsAction="always" />
</menu>
I know the alternative is to use the traditional onCreateOptionsMenu method.
Other alternative is to remove the line setSupportActionBar, but I need to show displayHomeAsUpEnabled.
Is it possible to use both myToolbar.inflateMenu() and setSupportActionBar simultaneously or is it incompatible?
When you use setSupportActionBar(), yes, you must solely use the ActionBar APIs and directly manipulating the Toolbar, be it by adding a Menu or other changes, are not supported.
If you don't want to use the ActionBar APIs, then don't call setSupportActionBar and use the Toolbar APIs directly (those are what the ActionBar APIs call anyways, so the Toolbar APIs are a superset of the ActionBar APIs already).
Toolbars have their own APIs for handling the navigation button (which is what displayHomeAsUpEnabled plugs into).
You can take advantage of this by adding the Up icon to your Toolbar:
<androidx.appcompat.widget.Toolbar
android:id="#+id/myToolbar"
android:layout_width="0dp"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navigationIcon="?attr/homeAsUpIndicator" />
Then you can get a callback on when the button is pressed by setting a click listener:
myToolbar.setNavigationOnClickListener {
// handle the navigation button
}

How to replace a fragment using NavController.navigate instead of adding it on top

I'm using the "new" Android Jetpack navigation, instead of relying on FragmentManager. I've got a simple main layout:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activities.MainActivity">
<FrameLayout
android:id="#+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="#id/bottomNav">
<fragment
android:id="#+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="#navigation/navigation_app" />
</FrameLayout>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottomNav"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="#menu/bottom_menu"
app:layout_constraintBottom_toBottomOf="#+id/root"/>
</android.support.constraint.ConstraintLayout>
And two additional layouts: "Splashscreen" with a TextView, "Login" with a button. The splashscreen fragment is used as starting point, and has a listener defined as follows:
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
textView.setOnClickListener{
findNavController(nav_host_fragment).navigate(R.id.action_splashScreenFragment_to_loginFragment)
}
}
screenshot
Instead of replacing TextView fragment with Button fragment, the Button fragment is stacked on top.
I've only encountered workarounds such as setting a background color, and clickable parameter, which I consider to be more of a hack, as I believe that the behaviour is exactly the same, but the fragment below is simply hidden. How to properly switch fragments using the NavController?
Issue seems to have occured because of these two lines:
val host = NavHostFragment.create(R.navigation.navigation_register_login)
supportFragmentManager.beginTransaction().replace(R.id.nav_host_fragment,host).setPrimaryNavigationFragment(host).commit()
I guess they shouldn't be called, and all basic requirements are fulfilled by this line in layout:
android:name="androidx.navigation.fragment.NavHostFragment"
You need to use popUpTo and popUpToInclusive to clear the backstack.
Check the Android Developers docs

My Fragment appears underneath the Toolbar regardless of how I change constraints

No matter how I add constraints, nothing changes in terms of my Fragment which contains a RecyclerView.
I have added a toolbar:
OnCreate in MainActivity
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)//TODO find inconsistencies
val demo = DemoDataBuilder()
// Set the toolbar as support action bar
setSupportActionBar(toolbar)
// Now get the support action bar
val actionBar = supportActionBar
// Set toolbar title/app title
actionBar!!.title = "AwezaMed"
// Set action bar/toolbar sub title
actionBar.subtitle = "App subtitle"
// Set action bar elevation
actionBar.elevation = 4.0F
toolbar.setNavigationIcon(R.drawable.ic_arrow_back_black_24dp)
toolbar.setNavigationOnClickListener { _ -> onBackPressed()}
startCategoryHome(savedInstanceState)
}
activity_main.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:layout_height="match_parent"
android:id="#+id/root_layout">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="?attr/colorPrimary"
android:minHeight="57dp"
android:padding="1dp"
app:layout_constraintTop_toTopOf="parent"
app:subtitleTextColor="#f5fbff"
app:titleTextColor="#fff" />
<fragment
android:id="#+id/categoyList_fragment"
android:name="za.co.aweza.awezamediphrases.fragments.CategoryListFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="112dp"
app:layout_constraintTop_toBottomOf="#+id/toolbar"
tools:layout="#layout/fragment_hcp_category" />
</android.support.constraint.ConstraintLayout>
You'll notice that in the layout code above, I have a very farfetched constraint that I tried to use.
Here is how it appears in designView:
But regardless of anything I try, the first cell of the RV in the Fragment sits mostly underneath the toolbar. What am I missing?
instead of fragment put this in your xml:
`<FrameLayout
android:id="#+id/frameLayout_fragment_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="#id/toolbar" />`
Replace the frame layout with any fragment you want using this function:
` fun openFragment(fragment: Fragment) {
val transaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.frameLayout_fragment_container, fragment)
transaction.addToBackStack(null)
transaction.commit()
}`
#EliodeBeirut's answer worked, but I found that changing the layout activity_main.xml from Constraint layout to Linear Layout worked as well.

Categories

Resources