Navbar appear 2 times when use databinding - android

Hi I am trying use the data-bitindng with the navbar for do it I have the next code:
MapActivity.java
public class MapActivity extends BaseActivity
implements NavigationView.OnNavigationItemSelectedListener, OnMapReadyCallback, GoogleMap.OnMarkerClickListener{
private static final float INITIAL_MAP_ZOOM_LEVEL = 17;
private static final int INITIAL_REQUEST_CODE = 1;
private GoogleMap mMap;
private CameraUpdate cameraUpdate = null;
private MapViewModel mapViewModel;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMapBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_map);
mapViewModel = ViewModelProviders.of(this).get(MapViewModel.class);
binding.setMapViewModel(mapViewModel);
binding.setLifecycleOwner(this);
NavHeaderMapBinding headerBinding = NavHeaderMapBinding.inflate(getLayoutInflater());
headerBinding.setMapViewModel(mapViewModel);
binding.navView.addHeaderView(headerBinding.getRoot());
setDrawerLayout();
setNavigationView();
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setMap();
setButtonEvents();
}
...
map_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable
name="mapViewModel"
type="com.emtmadrid.cardiomadapp.map.MapViewModel" />
</data>
<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:fitsSystemWindows="true"
tools:openDrawer="start">
<include
layout="#layout/app_bar_map"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header_map"
app:menu="#menu/activity_map_drawer" />
</android.support.v4.widget.DrawerLayout>
</layout>
app_nav_bar.xml
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable
name="mapViewModel"
type="com.emtmadrid.cardiomadapp.map.MapViewModel" />
</data>
<android.support.design.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:fitsSystemWindows="true"
tools:context=".map.MapActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#color/white"
app:popupTheme="#style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<include layout="#layout/content_map"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
</android.support.design.widget.CoordinatorLayout>
</layout>
When execute this code, I get the screen of the MapActivity but with 2 navbar, the first navbar databinding not work, and in the second navbar work perfectly.
How can solve this?
Any idea?
Thanks.

To solve the problem I dropped the following line in the app_nav_bar.xml
app:headerLayout="#layout/nav_header_map"

I'd like to challenge the accepted answer, because removing app:headerLayout appears counter-productive to me ...the data-binding is just missing the bind attribute on the include nodes:
<include
layout="#layout/app_bar_map"
android:layout_width="match_parent"
android:layout_height="match_parent"
bind:mapViewModel="#{mapViewModel}"/>
The same would go for this include, which should be moved outside of app_nav_bar.xml:
<include layout="#layout/content_map"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
bind:mapViewModel="#{mapViewModel}"/>
The result would be a working data-binding, where one only has to assign the MapViewModel once; the name-space for bind would be xmlns:bind="http://schemas.android.com/apk/res-auto".
When app_nav_bar.xml would only contain the AppBarLayout, it might be easier to handle; especially that include layout="#layout/content_map" appears quite confusing, in a file which is called app_nav_bar.xml. inflating the NavHeaderMapBinding is not required when having it already assigned with app:headerLayout - but the bind attribute is required, in order to have it bound.
Data-Binding Expressions: Includes also explains the combination of include & bind - which is generally less effort than inflating & binding several views by code - because inflating & binding the view once only works, when data-binding the include nodes properly with the layout resource XML. it's the actual beauty of data-binding, not having to bind all the includes by code.

Related

Where to add toolbar and navigation bar

I'm using android navigation controller.
My main activity hosts a nav fragment but where should other components like toolbars and nav bottom bar go, in the main activity or child fragments?
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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="#style/AppTheme.PopupOverlay" />
<fragment
android:id="#+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
app:defaultNavHost="true"
app:navGraph="#navigation/navigation" />
<android.support.design.widget.BottomNavigationView
android:id="#+id/bottom_nav_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="#menu/menu_bottom_nav" />
</LinearLayout>
fragment_home.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical" />
</RelativeLayout>
or should ToolBar and BottomNavigationView be in fragment_home.xml like so
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="#style/AppTheme.PopupOverlay" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical" />
<android.support.design.widget.BottomNavigationView
android:id="#+id/bottom_nav_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="#menu/menu_bottom_nav" />
</RelativeLayout>
I'll supply you with an example. Keep in mind, I'm compiling with the latest androidx for SDK 28+ so if you are on older, your namespaces will be slightly different.
I'm also using Databinding and Kotlin, so don't use the layout and data tags if you are not using databinding.
TOOLBAR
<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>
PUT BINDING VARIABLES HERE
</data>
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/SSTheme.AppBarOverlay">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
android:theme="#style/ToolbarTextAppearance">
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
MAIN ACTIVITY
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<data>
<variable name="activity" type="com.a35.activities.MainActivity"/>
<variable name="iBindingRecyclerView" type="com.a35.interfaces.IBindingRecyclerView"/>
</data>
<androidx.drawerlayout.widget.DrawerLayout
android:id="#+id/drawerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="false"
tools:openDrawer="start">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!--TOP TOOLBAR-->
<include
android:id="#+id/toolbarMain"
layout="#layout/toolbar_main"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<!--TOP BLACK LINE-->
<View
android:id="#+id/vRedLine"
android:layout_width="match_parent"
android:layout_height="#dimen/dp_2"
android:background="#color/black" />
<!-- FrameLayout is used to insert fragments to display -->
<FrameLayout
android:id="#+id/fragPlaceholder"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
</LinearLayout>
<com.google.android.material.navigation.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
android:background="#color/colorPrimary">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="#layout/nav_drawer_header"
android:id="#+id/navHeader"/>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/lstMenuItems"
android:layout_below="#+id/navHeader"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:bindRcvInterface="#{iBindingRecyclerView}"
app:bindRcvList="#{activity.getDrawerItemList}"/>
<ImageView
android:id="#+id/imgBottomLogo"
android:layout_width="#dimen/dp_160"
android:layout_height="#dimen/dp_35"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="#dimen/dp_35"
android:src="#drawable/scott_logo" />
</RelativeLayout>
</com.google.android.material.navigation.NavigationView>
</androidx.drawerlayout.widget.DrawerLayout>
</layout>
Notice the Main Activity holds Navigation View that is inside a drawer layout which contains the Recycler View for building your drawer content.
Outside of that you will see the content placeholder for fragments called fragPlaceHolder.
Lastly notice the parent layout is a LinearLayout with the first element being the include for the toolbar to include as we see fit.
Next your Styles. You'll need to use a style that does not rely on the action bar if you plan to use the toolbar as the actionbar. (for the record, you should be using the toolbar)
STYLE
<!--Full Screen-->
<style name="A35.FullScreen">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="android:windowFullscreen">true</item>
</style>
MANIFEST
<application
android:name=".application.A35Application"
android:allowBackup="true"
android:icon="#mipmap/a35_logo"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/A35.FullScreen">
You can also put it on individual Activities if that fits your need better.
Now you have two steps left.
You need to call setActionToolbar and pass your found UI or use synthetic views if you are using kotlin and databinding that is simple to do. So add in your onCreate AFTER inflating the view.
setSupportActionBar(toolbar)
You didn't ask this, but I'll supply it as well. When you need to change out your fragment, I typically have a BaseActivity with a helper method that does it like so.
protected fun swapFragment(fragment: BaseFragment, #Nullable bundle: Bundle?, hideCurrentFrag: Boolean = false) {
if (fragment.isVisible) {
A35Log.e(mClassTag, "swapFragment called on already visible fragment")
return
}
A35Log.v(mClassTag, "swapFragment( ${fragment.javaClass.simpleName} )")
val currentFragBundle = fragment.arguments
if (currentFragBundle == null && bundle != null) {
fragment.arguments = bundle
A35Log.v(mClassTag, "current bundle is null, so setting new bundle passed in")
} else if (bundle != null) {
fragment.arguments?.putAll(bundle)
A35Log.v(mClassTag, "current fragment bundle was not null, so add new bundle to it")
}
val fragmentManager = supportFragmentManager
fragmentManager.executePendingTransactions()
val fragmentTransaction = fragmentManager.beginTransaction()
//Make sure the requested fragment isn't already on the screen before adding it
if (fragment.isAdded) {
A35Log.v(mClassTag, "Fragment is already added")
if (fragment.isHidden) {
A35Log.v(mClassTag, "Fragment is hidden, so show it")
fragmentTransaction.show(fragment)
if(hideCurrentFrag) {
A35Log.v(mClassTag, "hideCurrentFlag = true, hiding current fragment $mSelectedFragment")
fragmentTransaction.hide(mSelectedFragment!!)
}else{
A35Log.v(mClassTag, "hideCurrentFlag = false, removing current fragment $mSelectedFragment")
fragmentTransaction.remove(mSelectedFragment!!)
}
}else{
A35Log.v(mClassTag, "Fragment is already visible")
}
}else if(mSelectedFragment == null){
A35Log.v(mClassTag,"mSelectedFragment = null, so replacing active fragment with new one ${fragment.javaClass.simpleName}")
fragmentTransaction.replace(R.id.fragPlaceholder, fragment)
}else{
A35Log.v(mClassTag, "Fragment is not added, so adding to the screen ${fragment.javaClass.simpleName}")
fragmentTransaction.add(R.id.fragPlaceholder, fragment)
if(hideCurrentFrag) {
A35Log.v(mClassTag, "hideCurrentFlag = true, hiding current fragment $mSelectedFragment")
fragmentTransaction.hide(mSelectedFragment!!)
}else{
A35Log.v(mClassTag, "hideCurrentFlag = false, removing current fragment $mSelectedFragment")
fragmentTransaction.remove(mSelectedFragment!!)
}
}
A35Log.v(mClassTag, "committing swap fragment transaction")
fragmentTransaction.commit()
A35Log.v(mClassTag, "mSelectedFragment = ${fragment.javaClass.simpleName}")
mSelectedFragment = fragment
}
NOTE* While swapping fragments is fairly universal, you need to make sure you are handling your needs properly. Should it be hiding, or removing. Should it be handling the bundles or ignoring them. The method I supplied you is basically showing if non-existent and hiding fragment instead of removing if told to hide it.
Handling building an adapter and list for the nav drawer and wiring up listener clicks on those items is not shown here as that was not your question and is beyond the scope of this question. I don't want to make my answer too bloated, so hopefully that is all you need to get going.
Happy Coding.

Android Data Binding conditional menu?

I'm try to set different menus based on the user's role using the data binding library.
In the fragment of code below you can see that if the user is an educator I would set the activity_main_educator_drawer otherwise the activity_main_child_drawer.
<?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"
xmlns:bind="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="user"
type="sc.me.twelve.viewmodels.UserViewModel" />
</data>
<android.support.v4.widget.DrawerLayout
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
layout="#layout/app_bar_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header_main"
app:menu="#{user.getModel.getRole.equals(`educator`) ? #menu/activity_main_educator_drawer : #menu/activity_main_child_drawer}" >
<include
layout="#layout/nav_header_main"
bind:user="#{user}" />
</android.support.design.widget.NavigationView>
</android.support.v4.widget.DrawerLayout>
</layout>
It seems good, but I have this error:
****/ data binding error ****msg:Identifiers must have user defined types from the XML file. activity_main_educator_drawer is missing it
FINALLY
The George Mount's answer is the right one, I've just added the BindingAdapter.
#BindingAdapter("app:menu")
public static void setMenu(NavigationView navigationView, int id) {
navigationView.inflateMenu(id);
}
It looks like the menu resource isn't being recognized. Try this expression instead:
<android.support.design.widget.NavigationView
...
app:menu="#{user.getModel.getRole.equals(`educator`) ? R.menu.activity_main_educator_drawer : R.menu.activity_main_child_drawer}" >
Make sure to import the R class:
<data>
<import type="sc.me.twelve.R"/>
</data>
or whatever your package is.
I see a small strangeness in your expression. I think it can be simplified:
app:menu="#{user.model.role.equals(`educator`) ? R.menu.activity_main_educator_drawer : R.menu.activity_main_child_drawer}"
The "get" or "is" prefix is assumed for accessor methods.

databinding must include a layout file

I have following very simple layout and wanted to switch to using data binding. Now I'm getting following error in my controller_main.xml:
Error:Execution failed for task ':app:dataBindingProcessLayoutsDebug_pro'.
****/ data binding error ****msg:[44 68 44 68 25] must include a layout
file:...\app\src\main\res\layout\controller_main.xml
****\ data binding error ****
Any ideas? The error says, the resource android:layout id in the include tag is missing (that's my interpretation of the error), but that's not true. Commenting out the include tag removes the error.
Does anyone see the problem?
controller_main.xml
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" >
<android.support.design.widget.CoordinatorLayout
android:id="#+id/coordinatorLayout"
android:fitsSystemWindows="true"
android:background="?attr/main_background_color"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<RelativeLayout
android:id="#+id/rlContent"
android:fitsSystemWindows="true"
android:layout_width="match_parent"
android:layout_height="match_parent">
</RelativeLayout>
<include
android:layout_width="fill_parent"
android:layout_height="#dimen/tool_bar_top_padding"
android:id="#+id/stub_view_main_header_fixed"
android:layout="#layout/view_main_header_fixed"
app:elevation="0dp"/>
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar" />
</android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout>
</layout>
view_main_header_fixed.xml
<?xml version="1.0" encoding="utf-8"?>
<View
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/vStatusbarBackground"
android:layout_width="match_parent"
android:layout_height="#dimen/tool_bar_top_padding" />
You should use layout instead of android:layout:
<include
android:layout_width="fill_parent"
android:layout_height="#dimen/tool_bar_top_padding"
android:id="#+id/stub_view_main_header_fixed"
layout="#layout/view_main_header_fixed"
app:elevation="0dp"/>
I had the exact same error, but for a different reason.
I was using <include> opening tag and </include> closing tag instead of <include for opening and /> for closing. It's little strange, but anyway your question helped me find my mistake. Thanks.

CoordinatorLayout messing up setError popup position

I'm facing an issue with EditText setError popup position.
I'm using the following code in to create the layout:
activity_profile.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.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:fitsSystemWindows="true"
tools:context=".ProfileActivity"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout android:layout_height="wrap_content"
android:layout_width="match_parent" android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar android:id="#+id/toolbar"
android:layout_width="match_parent" android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary" app:popupTheme="#style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<include layout="#layout/profile" />
</android.support.design.widget.CoordinatorLayout>
profile.xml
<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:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context=".ProfileActivity"
tools:showIn="#layout/activity_profile">
<EditText
android:id="#+id/etProfileName"
android:layout_width="match_parent"
android:layout_height="50dp"
android:capitalize="words"
android:hint="#string/et_hint_profile_name"
android:textAlignment="center" />
</RelativeLayout>
What I have tried
If I change the android.support.design.widget.CoordinatorLayout with LinearLayout the setError issue won't happen, but that will change the status bar color to white one and my UI is looking odd.
I'm new to Android programming and not sure what's going on, please help me.
What worked for me is an extra LinearLayout in activity_main.xml (yes, there):
<android.support.design.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:id="#+id/activityRoot"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="com.example.biptest.MainActivity">
<!-- *** THIS ONE *** -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/appbar"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="#style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<include layout="#layout/content_main" /> <!-- FRAGMENT(S) INSIDE -->
</LinearLayout>
<!-- *** BUT LEAVE THE FAB ALONE *** -->
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="#dimen/fab_margin"
android:src="#android:drawable/ic_dialog_email"
android:visibility="gone"
/>
</android.support.design.widget.CoordinatorLayout>
This also works around the layout bug that shows when you toggle visibility of a view in a fragment.
And the next problem is white-on-white error messages in the popup on Android 2.x (link)
I had the same problem. Testing a little bit the UI, I found that the problem appeared when the EditText widget gets the focus programatically to show the error, in my case calling .requestFocus(), but when focusing on the widget again manually the popup appeared correctly.
So my workaround was to delay the call to .requestFocus() in a Runnable (simulating a user clicking on the EditText widget).
Here is the code:
if (mFocusView != null) mFocusView.clearFocus(); // clear current focus. Needed to simulate a new "manual" focus
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
final Handler handler = new Handler();
final boolean b = handler.postDelayed(new Runnable() {
#Override
public void run() {
mFocusView.requestFocus(); // request focus
}
}, 1); // only delay 1 milisecond
}
});
mFocusView is the current EditText view to show an error.
Depending on your use case you may need to handle the focus when the keyboard is dismissed, as it makes the popup appear in the wrong position again.
Don't know if this will solve your problem. Hope it helps while Google solves this problem.
This was an Android bug and it is now fixed.
Reference : https://code.google.com/p/android/issues/detail?id=193793
Actually, the problem is not the CoordinatorLayout, but AppBarLayout.ScrollingViewBehavior. As a simple workaround you can remove the line app:layout_behavior="#string/appbar_scrolling_view_behavior" and add android:layout_marginBottom="?attr/actionBarSize" to your nested view if you don't need nested scroll.

'cannot find symbol variable' in android data binding include layout

layout_content.xml
<layout>
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
/>
</android.support.design.widget.AppBarLayout>
</layout>
layout_main.xml
<layout>
<android.support.v4.widget.DrawerLayout
android:id="#+id/dl_main_drawer"
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:fitsSystemWindows="true">
<include layout="#layout/layout_content" android:id="#+id/content"/>
</android.support.v4.widget.DrawerLayout>
</layout>
MainActivity.java
LayoutMainBinding binding = DataBindingUtil.setContentView(this,R.layout.layout_main);
setSupportActionBar(binding.content.toolbar);
Android Studio intellisense check binding.content is ViewDataBinding obj
but build error 'cannot find symbol variable content'
Will this have any problem?
thx!
The layout activity_main.xml:
<layout>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="#layout/layout_content" android:id="#+id/content" />
</LinearLayout>
</android.support.v4.widget.DrawerLayout>
</layout>
generates ActivityMainBinding.java. In your MainActivity.java, you use the generated field for content in the setSupportActionBar argument:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding binding = DataBindingUtil.setContentView(this,R.layout.activity_main);
setSupportActionBar(binding.content.toolbar);
}
Normally a layout will generate public final fields for each of the Views with android:ids and Binding subclasses for each of the includes with IDs. In this case, the data binding system did not detect that the included content #layout/layout_content was a binding layout and thus didn't capture the Binding class for the include.
When a variable is bound to an include, the data binding system will use that to determine that the included layout is a binding layout. So, if your layout had this instead:
<include layout="#layout/layout_content"
android:id="#+id/content"
app:someVar="#{someVar}" />
You'd have gotten a content field with the type LayoutContentBinding. This does assume that someVar is declared in both activity_main.xml and layout_content.xml.
The error in Android Studio was pointing to the correct location, but it was difficult to understand. In the future, you can look for the generated binding class in your app/build directory. This may help you figure out what the error means.
I've filed a bug to fix the error -- we should be generating a public final field for the include with the ID.

Categories

Resources