I have an activity and a few fragments in it, and I have an action bar that I need to be visible all the time except for the case when I open MyTestFragment, so when I open this fragment I need my action bar to be hidden.
As my Activity is AppCompatActivity, I tried to call this method (from Activity) in order to hide an actionBar
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity)
supportActionBar?.hide()
...
and it works, however, I need to make this call from fragment, so I do it like this
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
(activity as AppCompatActivity).supportActionBar!!.hide()
}
and the result is
The action bar became kind of invisible instead of gone (you see this gray pass right under the clock)
What am I missing here?
UPD
I would like to add explanation to the problem, in order to illustrate this I did such code:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity)
Thread {
Thread.sleep(8000)
mainExecutor.execute {
supportActionBar?.show() <---- 2
}
}.start()
Thread {
Thread.sleep(12000)
mainExecutor.execute {
supportActionBar?.hide() <---- 3
}
}.start()
supportActionBar?.hide() <---- 1
...
What is happening here is - the method marked 1 is invoking first and the actionbar hides as expected. The next method #2 invokes show() for the action bar and the action bar appears as expected, however, when it comes to method #3 and tries to hide the actionbar again the bug is here. Instead of hiding the actionbar it kind of makes it invisible and you can see a grey line (like on the screenshot).
So, looks like it is possible to hide the actionbar only immediately in OnCreate() method if you try to do it after you will see a grey line instead of the actionbar.
UPD
My MainActivity.xml
<?xml version="1.0" encoding="utf-8"?>
<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:id="#+id/awl_application_drawerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/main_activity_layout_bg_color"
tools:openDrawer="end">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<application.widget.toolbar.BondToolbarLayout
android:id="#+id/toolbar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<FrameLayout
android:id="#+id/errorViewContainer"
android:layout_below="#id/toolbar_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
<FrameLayout
android:id="#+id/fragment_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/toolbar_layout"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.tabs.TabLayout
android:id="#+id/tab_layout"
style="#style/AppTabLayout"
android:layout_width="match_parent"
android:layout_height="#dimen/bottom_nav_tab_height"
android:background="#color/deprecated_palette_FF000000"
android:elevation="6dp"
android:fillViewport="true"
android:padding="0dp"
app:tabPaddingBottom="0dp"
app:tabPaddingEnd="0dp"
app:tabPaddingStart="0dp"
app:tabPaddingTop="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:tabMinWidth="#dimen/bottom_nav_tab_min_width" />
<CustomView
android:layout_width="match_parent"
android:layout_height="0dp"
android:visibility="invisible"
app:layout_constraintBottom_toTopOf="#id/tab_layout"
app:layout_constraintTop_toTopOf="parent"
app:theme="#style/ThemeOverlay.AppCompat.Light" />
</androidx.constraintlayout.widget.ConstraintLayout>
<FrameLayout
android:id="#+id/navigation_view_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="end"
android:layout_marginTop="?android:attr/actionBarSize" />
</androidx.drawerlayout.widget.DrawerLayout>
When navigating to TestFragment, do supportActionBar?.hide() from Activity.
Do supportActionBar?.show() from Activity when navigating to the Fragment where the ActionBar should be visible.
I've done something like this in a project but on an Activity but you can do the similar thing on Fragments also
Here I've created a method called "setupToolbar" which I call from onCreate right after setContentView(R.layout.___)
private fun setupToolbar() {
toolbar.title = ""
setSupportActionBar(toolbar)
toolbar.navigationIcon = ContextCompat.getDrawable(this, R.drawable.arrow_back_white_24)
toolbar.setNavigationOnClickListener {
finish()
}
supportActionBar?.hide()
}
Then I added a gesture listener and observing SingleTap
private var gestureListener: GestureDetector.SimpleOnGestureListener =
object : GestureDetector.SimpleOnGestureListener() {
override fun onSingleTapUp(e: MotionEvent?): Boolean {
if (toolbar.visibility == View.VISIBLE) {
supportActionBar?.hide()
return true
} else {
supportActionBar?.show()
}
return false
}
}
There might be two options here.
Defining topbar in each fragment layout and don't include in specific fragment where not required, rather than including in activity.
OR
Define some NO ACTION BAR styles in style.xml, then set/unset it in java/kotlin code, when navigating to/from some fragment.
In styles.xml :
<style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
In kotlin/java code from activity:
Call setTheme method with above defined style and then call recreate()
Related
everyone. I have a BottomnNavigationsBar and a FrameLayout inside my activity_main.xml file. In the frame I display a ViewPager within a Fragment. The navigation contains 3 elements. If I click on one, the clicked status does not change. The respective fragment is displayed correctly, but the icon does not change in color and size.
What am I doing wrong or what do I have to change?
Here is my MainActivity:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewBinding = ActivityMainBinding.inflate(layoutInflater)
setContentView(viewBinding.root)
setFragementTo(HomeFragment.newInstance("",""))
viewBinding.bottomNavigationView.setOnItemSelectedListener{
when(it.itemId)
{
R.id.home ->{
setFragementTo(HomeFragment.newInstance("",""))
}
R.id.neu ->{
setFragementTo(NewFragment.newInstance("",""))
}
R.id.settings ->{
setFragementTo(FilterFragment.newInstance("",""))
}
}
false
}
}
private fun setFragementTo(fragment: Fragment) {
supportFragmentManager.beginTransaction().replace(R.id.myFrameInMain,fragment).commit()
}
activity_main.xml:
<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">
<FrameLayout
android:id="#+id/myFrameInMain"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="#+id/bottomNavigationView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"></FrameLayout>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:background="#drawable/bottom_nav_style"
app:itemRippleColor="#color/white"
app:itemTextColor="#color/item_bottom_nav"
app:itemIconTint="#color/item_bottom_nav"
android:id="#+id/bottomNavigationView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:menu="#menu/bottom_nav"/>
</androidx.constraintlayout.widget.ConstraintLayout>
Here I click on the middle icon in the navigation. The fragment appears correctly, but the icon in the navigation does not
And here the filter icon:
I think I got it. I had to change the parameter from false to true in the setOnItemSelectedListener method
In my app, there is an activity which needs to be closed on navigation click. In the past, the code below worked perfectly, however, since the new Android changes it doesnt work anymore.
Are there new ways to call the Navigation icon click? Is there something i am missing?
ActivitySettings.kt
class ActivitySettings : AppCompatActivity() {
private lateinit var binder: ActivitySettingsBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binder = ActivitySettingsBinding.inflate(layoutInflater)
setContentView(R.layout.activity_settings)
binder.topToolbarBack.setNavigationOnClickListener {
finish()
}
}
}
activity_settings.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"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.MaterialToolbar
android:id="#+id/topToolbarBack"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:navigationIconTint="#color/white_material"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navigationIcon="#drawable/ic_outline_arrow_back_24"
app:popupTheme="#style/popupMenuThemeDark"
app:title="#string/currentScreenSettings"
app:titleTextColor="#color/white_material" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rvSettings"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="#+id/topToolbarBack" />
</androidx.constraintlayout.widget.ConstraintLayout>
please make sure you call setSupportActionBar(binder.topToolbarBack) before you set click listener for the toolbar
This problem is caused by the way the layouts got called.
binder can be considered a "secondary layout". Since in that activity, i set as ContenteView R.layout.activity_settings, the binder, that can still get the elements from the layout, gets basically covered by the layout currently set.
If you want to use binder you must set as inside setContentView() binder.root, which loads the proper layout you need.
So, the code fixed is:
class ActivitySettings : AppCompatActivity() {
private lateinit var binder: ActivitySettingsBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binder = ActivitySettingsBinding.inflate(layoutInflater)
setContentView(binder.root)
binder.topToolbarBack.setNavigationOnClickListener {
finish()
}
}
}
I want to create a Bottom Navigation Bar. I used android BottomNavigationView to create the UI but I don't know how to add an OnClick listener to the items in Menu.
I searched on google and found some articles, but all of them were using a Toolbar element. I don't know about how to add that and what it was doing.
This is my Navigation bar code which I am including in the main activity
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:design="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout android:layout_width="match_parent" android:id="#+id/bottom_nav"
android:background="#drawable/gradient_theme"
android:layout_height="wrap_content" android:layout_gravity="bottom">
<android.support.design.widget.BottomNavigationView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/white"
android:id="#+id/menuBar"
design:menu="#menu/menu_bar"
design:itemIconTint="#android:color/darker_gray"/>
</RelativeLayout>
</FrameLayout>
This is my MainActivity.kt in which i want to set Listeners
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
beautifyLayout(this, window)
setSupportActionBar(toolbar)
testButton.setOnClickListener {
val intent= Intent(this,AccountActivity::class.java)
finish()
startActivity(intent)
}
}
}
This is menu_bar.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="#+id/btn1" android:title="" android:icon="#drawable/ic_feed"/>
<item android:id="#+id/btn2" android:title="" android:icon="#drawable/ic_chat_bubble_black_24dp"/>
<item android:id="#+id/btn3" android:title="" android:icon="#drawable/ic_search_black_24dp"/>
<item android:id="#+id/btn4" android:title="" android:icon="#drawable/ic_menu_black_24dp" />
</menu>
The UI is working perfectly ,it only requires some Listeners. I want if possible to use only BottomNavigationView.
This is how you set the listener:
val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener { item ->
when (item.itemId) {
R.id.btn1 -> {
// put your code here
return#OnNavigationItemSelectedListener true
}
R.id.btn2 -> {
// put your code here
return#OnNavigationItemSelectedListener true
}
R.id.btn3 -> {
// put your code here
return#OnNavigationItemSelectedListener true
}
R.id.btn4 -> {
// put your code here
return#OnNavigationItemSelectedListener true
}
}
false
}
menuBar.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener)
If menuBar is inside your activity's layout it does not need initialization.
If not, you must use findViewById() to initialize it.
I have a TabLayout with two fragments which both of them shows a RecyclerView (one movies and the other tv shows). The TabLayout works perfectly but the problem comes when I click on the image of a film. The click in a movie should make a transaction to the movie details fragment. But when this happens the ListFragment with the TabLayout appears under the new one so the two of them are displayed.
My ActivityMain code where I call the transaction and where I set the Page Adapter:
override fun onMovieClicked(iDMovie: Int) {
val movieDetails = MovieDetailsFragment.newInstance(iDMovie)
supportFragmentManager.
beginTransaction().
replace(R.id.main_container, movieDetails).
addToBackStack(null).
commit()
}
private fun setStatePageAdapter() {
val fragmentAdapter = MyPagerAdapter(supportFragmentManager)
viewPager.adapter = fragmentAdapter
tabLayout.setupWithViewPager(viewPager)
}
My PageAdapterClass:
class MyPagerAdapter(fm: FragmentManager): FragmentPagerAdapter(fm) {
override fun getItem(position: Int): Fragment {
return when (position) {
0 -> {
ListFilmFragment()
}
else -> {
return TVShowsFragmentList()
}
}
}
override fun getCount(): Int {
return 2
}
override fun getPageTitle(position: Int): CharSequence {
return when (position) {
0 -> "PelĂculas"
else -> {
return "Series"
}
}
}
}
And the Layouts:
Activity Main:
<android.support.design.widget.CoordinatorLayout
android:id="#+id/main_container"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.TabLayout
android:id="#+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?actionBarSize"
app:tabGravity="fill"
app:tabIndicatorHeight="4dp"
app:tabBackground="#color/black"
app:tabMode="fixed"
app:tabTextColor="#color/white"
app:layout_scrollFlags="scroll|enterAlways">
</android.support.design.widget.TabLayout>
<android.support.v4.view.ViewPager
android:id="#+id/viewPager"
android:layout_height="match_parent"
android:layout_width="match_parent">
</android.support.v4.view.ViewPager>
Observation: With FrameLayout instead of Coordinator didn't work either.
The result I get is the following:
The FragmentDetails overlaps the filmListFragment and the two of them are displayed at the same time. But only the details fragments has to be displayed.
You can solve your problem in 2 ways
first:
You can hide your ViewPager and TabLayout befor inflating Your fragments.
so change your MovieClicked method like below
override fun onMovieClicked(iDMovie: Int) {
viewPager.visibiliy=View.Gone;
tabLayout.visibility=View.Gone
val movieDetails = MovieDetailsFragment.newInstance(iDMovie)
supportFragmentManager.
beginTransaction().
replace(R.id.main_container, movieDetails).
addToBackStack(null).
commit()
}
Seconde:
You can change your fragments XML Root elements
1-set a background for each of you fragments android:background="yourColor" to hide
behind layout .
2-set OnClick attribute to true to make app receive your current layout
onClickListeners not behind layout with android:onClick=true
Your Xml must be like below
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:onClick="true"
android:background="#ffffff"<!--White Color for example-->
>
</android.support.design.widget.CoordinatorLayout>
If you have several fragment layout that has your problem
You can set an style and change your fragment style to your style
So declare an style in style.xml
<style name="fragmentsRootElementStyle">
<item name="android:onClick">true</item>
<item name="android:background">#ffffff</item>
</style>
and set style for fragment layouts root as below
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
style="#style/fragmentsRootElementsStyle"
>
</android.support.design.widget.CoordinatorLayout>
I'm trying to abstract my Navigation Drawer to streamline my Android app but I'm running into some issues. The Nav Drawer simply doesn't respond to touches, I can't figure out why.
MainActivity.kt
class MainActivity : NavActivity() {
/** ON CREATE **/
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
main_seekbar_price!!.setOnSeekBarChangeListener(this)
mDrawerLayout = findViewById(R.id.drawer_layout) // Variable in superclass
...
NavDrawer.kt
abstract class NavActivity : BaseActivity() {
/** Variables **/
lateinit var mDrawerLayout: DrawerLayout
/** ON CREATE **/
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_nav)
// Set Nav Drawer listener
nav_view.setNavigationItemSelectedListener { menuItem ->
Log.d("NAV", "nav selected listener header")
menuItem.isChecked = true
mDrawerLayout.closeDrawers()
navMenuSwitch(menuItem)
true
}
// Set Nav Footer listener
nav_footer.setNavigationItemSelectedListener { menuItem ->
Log.d("NAV", "nav selected listener footer")
menuItem.isChecked = false
mDrawerLayout.closeDrawers()
navMenuSwitch(menuItem)
true
}
}
...
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.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:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/colorBackground"
android:fitsSystemWindows="true"
tools:context=".MainActivity">
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" >
...
</FrameLayout>
<include layout="#layout/activity_nav" />
</android.support.v4.widget.DrawerLayout>
activity_nav.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.NavigationView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:menu="#menu/drawer_header"
app:headerLayout="#layout/nav_header">
<android.support.design.widget.NavigationView
android:id="#+id/nav_footer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
app:menu="#menu/drawer_footer">
</android.support.design.widget.NavigationView>
</android.support.design.widget.NavigationView>
I thought it has something to do with assigning mDrawerLayout in the child class but that didn't fix anything. It never calls the listeners though, no matter how much you click it it won't even print Logs in that listener.
Any help is welcome as I can't figure this out for the life of me, thank you in advance!
Four things happen, in this order, when your MainActivity's onCreate() is called:
MainActivity's content view is set by inflating activity_nav.xml.
The nav_view and nav_footer Kotlin variables are assigned by searching the content view for them. (Kotlin does this for you, so it's easy to forget that it's happening.)
Listeners are attached to the nav_view and nav_footer views.
MainActivity's content view is set again, this time by inflating activity_main.xml. (The include tag inside activity_main.xml tells the framework that it should inflate another copy of activity_nav.xml as part of the process.) The old content view is overwritten.
So by the time MainActivity.onCreate() finishes, the views with listeners attached are gone. One way to fix the problem would be to delete the line setContentView(R.layout.activity_nav) from NavActivity.onCreate() and to move the rest into an initNavDrawerListeners() method that's called from MainActivity.onCreate().