Android layout in preview different when I execute the app - android

I made an app with a fragment and a recyclerviw inside.
The Fragment layout is this
<?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="homeViewModel"
type="com.phatedev.eliquidcalculator.ui.home.HomeViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/e_liquid_list"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:listData="#{homeViewModel.eLiquids}"
tools:listitem="#layout/list_e_liquid_item" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
and the layout of the single row list_e_liquid_item is
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="eLiquid"
type="com.phatedev.eliquidcalculator.domains.ELiquid" />
</data>
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="120dp"
android:layout_margin="8dp"
android:backgroundTint="#00AA44">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<!-- Title, secondary and supporting text -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#{eLiquid.name}"
tools:text="Banana, Fragola, Ananas"
android:textAppearance="?attr/textAppearanceHeadline6" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="#{eLiquid.description}"
tools:text="https://www.netflix.com/watch/80111460?trackId=155573558"
android:textAppearance="?attr/textAppearanceBody2"
android:textColor="?android:attr/textColorSecondary" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="#{eLiquid.base}"
tools:text="80/20"
android:textAppearance="?attr/textAppearanceBody2"
android:textColor="?android:attr/textColorSecondary" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
</layout>
In the Android Studio preview everything look perfect, as you can see in this screenshot that I take on Android Studio
but when I run the app on the emulator the layout is broke and I don't understand what I'm doing wrong
EDIT:
The app:listData="#{homeViewModel.eLiquids}" in RecyclerView is this bind function
#BindingAdapter("listData")
fun bindRecyclerView(recyclerView: RecyclerView, data: List<ELiquid>?) {
val adapter = recyclerView.adapter as ELiquidAdapter
adapter.submitList(data)
}
EDIT: Ok, I found a solution to my problem here but can someone explain me why it work?

You didn't share your adapter code, but the issue would likely be that you are inflating the item view without "parent" parameter. I have faced the same issue and below are the changes I have made to fix the problem.
Before:
No parent parameter specified - list item width will be set to wrap content even though set to match parent in the xml.
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(ListViewItemBinding.inflate(LayoutInflater.from(parent.context)))
}
After:
Specified 'parent' parameter and the list item is inflated properly matching the parent view. Also parameter false is added, as recycler view will be attaching the view.
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(ListViewItemBinding.inflate(LayoutInflater.from(parent.context),parent, false))
}

It also differs from phone to another because of the density variations
edit your layout to matchparent the width
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="8dp"
android:backgroundTint="#00AA44">

try to change in your activity.xml
<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"
app:headerLayout="#layout/nav_header_main"
app:menu="#menu/activity_main_drawer" />
to
<com.google.android.material.navigation.NavigationView
android:id="#+id/nav_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header_main"
app:menu="#menu/activity_main_drawer" />

Actally i have also faced same kind of problem it looks fine in preview must while run ii it is getting wrap around so what i did is.please add dummy match_parent View like below in your linearlayout of list_e_liquid_item file.
<View
android:layout_width=match_parent
android :layout_height= 1dp
/>
Please let me know if it doent work.

Related

ViewStub inflation of ConstraintLayout

I want to leverage ViewStub to optionally show a portion of UI. When the root of my inflated item is ConstraintLayout then it doesn't render.
But if that root is MaterialCardView then it displays as intended.
<!-- my_fragment.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:id="#+id/fragmentRootLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ViewStub
android:id="#+id/fragmentViewStub"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inflatedId="#+id/fragmentViewStub"
android:layout="#layout/item"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<!-- item.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:id="#+id/itemRootLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.textview.MaterialTextView
android:id="#+id/itemLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/itemLabelText"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
/* MyFragment.kt */
#AndroidEntryPoint
class MyFragment : Fragment(R.layout.my_fragment) {
private val viewModel: MyViewModel by viewModels()
private val viewBinding: MyFragmentBinding by viewLifecycleLazy {
MyFragmentBinding.bind(requireView())
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewBinding.fragmentViewStub.inflate()
}
}
I've tried matching the ViewStub's id/inflatedId attributes and programmatically setting dimensions/constraints but neither solved the issue.
What am I overlooking about making these pieces work together?
Forgot to update with my answer/oversight. This worked as expected in both cases all along.
Nightmode was enabled and the behavior of MaterialCardView has automatic contrast between its card and content. Meanwhile, when ConstraintLayout inverts its theme the label appears to be missing but is indeed present, as white text on white background.

Why app namespace doesn't have autocompletion in just one of my Android project layouts?

When I put "app:" in main_activity.xml, doesn't work the autocompletion, it only shows 1 option:
appNs
But when I do in another xml like fragment_owl.xml, it gives me all the attributes of app namespace.
I have xmlns:app="http://schemas.android.com/apk/res-auto in both of them
this are my xmls
activity_main.xml: (that has autocompletion of app namespace attributes)
<?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">
<TextView
android:id="#+id/holamundo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="69dp"
android:text="Hola Mundo"
android:textAllCaps="false"
android:textSize="36sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/roll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="134dp"
android:text="GIRAR"
android:textSize="36sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<ImageView
android:id="#+id/dice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="#drawable/empty_dice"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:srcCompat = "#drawable/dice_1"
/>
<!-- android:src="#drawable/dice_1"-->
</androidx.constraintlayout.widget.ConstraintLayout>
but in this another one:
<?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"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<fragment
android:id="#+id/navHostFragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:navGraph="#navigation/navigation"
app:defaultNavHost="true"
app <- NO AUTOCOMPLETION :(
/>
</LinearLayout>
</layout>
I've already try invalite cache and delete or override some folders but nothings seems to work for me.
After doing some digging i found out the following
Changing your LinearLayout to a ConstraintLayout solves your problem, but why?
ConstraintLayout is from a library (you import it via your build.gradle androidx.constraintlayout:constraintlayout:*.*.*)
CommonsWare explains it here android.support.constraint is from a library, not the platform.
Taking this into account Android Studio maybe doesnt understand the app namespace for layouts that belong to the Android platform like LinearLayout as they are part of the android namespace.
This is my interpretation, hope it answers your question
Faced same issue here what worked for me
Click Blue stack icon (present in top left corner of layout preview) -> Force Refresh Layout
Set Constraints by dragging constraints in Layout preview window once
Now suggestions should start appearing again.

Android Databinding view tag isn't correct on view:null

the question tag may be familiar in stackoverflow but I have some situation here. I want to achieve that my app will have a bottom menu bar which will be visible across the application. So I added a view and set it on my base activity Like following
#Override
public void setContentView(int layoutResID) {
fullLayout = (RelativeLayout) getLayoutInflater().inflate(R.layout.activity_base, null);
configureToolbar(fullLayout);
subActivityContent = (FrameLayout) fullLayout.findViewById(R.id.content_frame);
getLayoutInflater().inflate(layoutResID, subActivityContent, true);
super.setContentView(fullLayout);
}
Previously it was like:
#Override
public void setContentView(int layoutResID) {
View view = getLayoutInflater().inflate(layoutResID, null);
configureToolbar(view);
super.setContentView(view);
}
Now on some page there is data-binding. Which is called like following:
viewModel = new MyViewModel(someId, someName, false, emptyString);
binding = DataBindingUtil.setContentView(this, R.layout.activity_my_layout);
binding.setItem(viewModel);
Now I am getting error on 2nd line.
Here is my activity layouts. 1st one is common layout which is activity_base, 2nd one is data binding Layout.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_height="match_parent">
<include android:id="#+id/app_bar" layout="#layout/app_bar" />
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.roughike.bottombar.BottomBar
android:id="#+id/bottomBar"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_alignParentBottom="true"
app:bb_tabXmlResource="#xml/bottombar_tabs" />
2nd layout:
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:map="http://schemas.android.com/apk/res-auto">
<data>
<import type="android.view.View" />
<variable
name="item"
type="io.ppp.views.someActivity" />
</data>
<RelativeLayout
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/root_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="io.ppp.views.someActivity">
<include android:id="#+id/app_bar" layout="#layout/app_bar" />
<!--<include layout="#layout/activity_base" />-->
<WebView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/webViewLoader"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<RelativeLayout
android:id="#+id/progress_indicator"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="false"
android:layout_centerInParent="true"
android:visibility="#{item.loading ? View.VISIBLE : View.GONE}">
<ProgressBar
android:id="#+id/search_progress"
style="#style/Base.Widget.AppCompat.ProgressBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:indeterminate="true" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_gravity="center"
android:layout_marginTop="50dp"
android:text="#{item.loadingText}"
android:textAppearance="?android:attr/textAppearanceSmall" />
</RelativeLayout>
</RelativeLayout>
I don't think this is a good solution to implement a bottom navigation bar across your application since you are creating Activities, and it will be clear to the user that every time you change activity the screen will totally swap (bottom bar included) instead of keeping a fixed element in the bottom of the screen which the user will use to guide himself across the application.
Implementing Bottom Navigation in Android is much trickier than it is in iOS since you are going to have to work with ONE SINGLE Activity and Fragments(Lots of them if you have a lot of screens) to achieve a smooth bottom navigation like application.
My advice to you is to transform your activities into fragments, implement the bottom navigation Activity with the bottom bar and a fragment container, and go from there.
From API 25 it was introduced the BottomNavigationView which will make your life easier and you won't need to use BottomBar library from GitHub. I also advice to look at AHBottomNavigation, it seems to me more complete than the native one, gives you a better control and choices over your bottom bar.

Data-bound visibility for RecyclerView's empty view has no effect

I'm trying to implement an empty view solution for a RecyclerView via data binding based on this solution. I have a RecyclerView and RelativeLayout (the empty view) within a SwipeRefreshLayout. Here is the XML for the layout:
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<import type="android.view.View"/>
<variable
name="dataset"
type="...SeriesList"/>
</data>
<android.support.v4.widget.SwipeRefreshLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/list"
android:name="...SeriesFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
android:layout_marginTop="10dp"
app:layoutManager="LinearLayoutManager"
tools:context=".fragments.SeriesFragment"
android:visibility="#{dataset.size() > 0 ? View.VISIBLE : View.GONE}"/>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/empty_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="#{dataset.size() > 0 ? View.GONE : View.VISIBLE}">
<TextView
android:id="#+id/empty_text"
style="#style/Base.TextAppearance.AppCompat.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="#+id/empty_image"
android:layout_centerHorizontal="true"
android:layout_marginBottom="10dp"
android:width="300dp"
android:gravity="center"
android:textColor="#59000000" />
<ImageView
android:id="#+id/empty_image"
android:layout_width="128dp"
android:layout_height="160dp"
android:layout_centerInParent="true"
android:src="#drawable/empty" />
</RelativeLayout>
</android.support.v4.widget.SwipeRefreshLayout>
</layout>
As you can see the RelativeLayout after the RecyclerView is the empty view, with their visbilities based on the size of the dataset, which is a SeriesList (extends ObservableArrayList). In the fragment containing this layout I bind the data like so:
FragmentSeriesListBinding binding = FragmentSeriesListBinding.inflate(inflater);
binding.setDataset(getmAdapter().getVisibleSeries());
So based off of this, I'm assuming when the adapter's visible SeriesList is empty, the visibilities of the RecyclerView will be GONE and the empty view will be VISIBLE. Upon testing with an empty dataset both the RecyclerView (with no items) and the empty view have a visibility of VISIBLE, which shouldn't be possible. Could someone shed some light as to why this isn't working as I expect?
So I ended up fixing this after reading here that SwipeRefreshLayout must have one child, so I wrapped the RecyclerView and RelativeLayout in a FrameLayout. I also used this solution to inflate the Fragment's layout with the DataBindingUtil inflate() method and setting the binding in the Fragment's onCreateView() method.

NextFocus editText in include layout

I create a simple layout containing my label and my editText. This layout is included several time to create a form.
But with this method the "nextFocus" function doesn't work properly and I can't find a solution. I need to give the id of the next editText but because it's inside a include layout, the id is the same as the current editText.
Is their a way to achieve this by using only xml solution? I particulary think of databinding.
This is my layout's :
The include layout :
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="viewModel"
type="viewModels.StringDataTypeViewModel"/>
<variable
name="nextFocus"
type="Integer"/>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
tools:text="Nom de famille : "
android:text="#{viewModel.label}"
android:singleLine="true"
android:ellipsize="end"/>
<EditText android:id="#+id/value"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="#dimen/patient_detail_edittext_text_size"
android:inputType="textPersonName"
android:ellipsize="end"
tools:text="Dupont"
android:text="#={viewModel.value}"
android:textColor="#android:color/widget_edittext_dark"
android:clickable="#{viewModel.editable}"
android:cursorVisible="#{viewModel.editable}"
android:focusable="#{viewModel.editable}"
android:focusableInTouchMode="#{viewModel.editable}"
android:background="#{viewModel.editable ? #android:drawable/edit_text : #drawable/empty_drawable}"
android:nextFocusForward="#id/value"/>
</LinearLayout>
The form layout :
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="#{viewModel.editable ? View.VISIBLE: View.GONE}">
<include layout="#layout/string_data_type_layout"
app:viewModel="#{viewModel.familyNameViewModel}" />
<include layout="#layout/string_data_type_layout"
app:viewModel="#{viewModel.givenNameViewModel}" />
<include layout="#layout/string_data_type_layout"
app:viewModel="#{viewModel.patientCodeViewModel}" />
<include layout="#layout/string_data_type_layout"
app:viewModel="#{viewModel.addressViewModel}" />
</LinearLayout>
Step 1: Give unique ids to all your include elements
<include android:id="#+id/edit_text_1"
... />
<include android:id="#+id/edit_text_2"
... />
Step 2: Add these attributes to the root of your included layout xml (LinearLayout in your case)
<LinearLayout
android:descendantFocusability="afterDescendants"
android:focusableInTouchMode="true"
... />
Step 3: Use the ids defined in step 1 in all your include elements (as per required navigation)
<include android:id="#+id/edit_text_1"
app:nextFocus="#{#id/edit_text_2}"
... />
Cheers!
Can you try to change the id of EditText?
This is work for me:
1.The include Layout:
<layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
...
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
...>
...
<EditText android:id="#+id/et_common"
.../>
</LinearLayout>
2.Create an id in ids.xml
<item name="next_focus_et" type="id"/>
3.Set next focus on another view
<Button
android:id="#+id/btn"
android:nextFocusUp="#id/next_focus_et"
.../>
4.Change the id of EidtText to "next_focus_et" in the code.
private void initComplexNextFocus(){
mBinding.includeStaticDns2Edit.et_common.setId(R.id.next_focus_et);
}

Categories

Resources