I have multiple layouts that are defined in hierarchical order, The issue is when i try to access item that is defined in an inner layout, it gives me NullPointerException.
This is my layout structure.
R.layout.activity_map
-> <include layout="content_map">
-> <include layout="terrace_parent_map">
-> <include layout="terrace_collection_map">
Now terrace_collection_map has constraint layout, that i need to access from the activity.
Following is the layout.
<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="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/constraintTerraceLayout"
>
</android.support.constraint.ConstraintLayout>
But when i try to get id of constraintLayout, it returns null.
constraintTerraceLayout= findViewById(R.id.constraintTerraceLayout);
**Edit - terrace_collection_map **
<?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="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/constraintTerraceLayout"
>
<ImageView
android:id="#+id/imageView30"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:background="#drawable/terrace" />
</android.support.constraint.ConstraintLayout>
Try by adding the <merge /> tag that helps you to eliminate redundant view groups in your view hierarchy when including one layout within another.
For example, if your main layout is a vertical LinearLayout in which two consecutive views can be re-used in multiple layouts, then the re-usable layout in which you place the two views requires its own root view.
So use <merge> tag, if activity_map.xml has LinearLayout as a parent tag. Then change your terrace_collection_map.xml parent tag as like below code :
<merge xmlns:android="http://schemas.android.com/apk/res/android">
//..........Your Custom Layout Design...........
</merge>
This link helps you briefly, https://developer.android.com/training/improving-layouts/reusing-layouts
Related
I have a fragment that has a CoordinatorLayout type of the main layout
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.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">
<include
android:id="#+id/secondContainer"
android:layout_height="match_parent"
android:layout_width="match_parent"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"/>
<include
android:id="#+id/mainContainer"
layout="#layout/view_home_content"
app:layout_anchorGravity="bottom"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
So inside the main container I got two included separate layouts. First one
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/topContainer"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Button
android:id="#+id/topButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</androidx.constraintlayout.widget.ConstraintLayout>
And the bottom one
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/bottomContainer"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="#+id/bottomText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</androidx.constraintlayout.widget.ConstraintLayout>
So my main goal is to make view with id topButton constraint to bottom of bottomText. I was trying to make it programmatically and it works fine if they are In the same xml file but when they are separate as I show above it doesn't work
Here is how I programmatically connects them
with(binding.topContainer) {
topContainer = topContainer
button = topButton
}
with(binding.bottomContainer) {
text = bottomText
}
val mConstraintSet = ConstraintSet()
mConstraintSet.clone(topContainer)
mConstraintSet.clear(R.id.topButton, ConstraintSet.TOP)
mConstraintSet.connect(R.id.topButton, ConstraintSet.TOP, R.id.bottomText, ConstraintSet.BOTTOM)
mConstraintSet.applyTo(topContainer)
As I said earlier it works if I use ID's of layouts from one file. But this way seems they don't see each other
It's expected that It won't work when using the two separate files. To use constraints, you need to put the desired views inside the same constraint layout. You have a ConstraintLayout for bottom and another for top. You can try to put a ConstraintLayout inside your coordinatorLayout and try to put the constraints in include tags.
I was planning on having two layout versions for the profile fragment, one for new user and one for logged in user.
How would I dynamically switch/choose the necessary layout in the Fragment's onCreateView() method?
The most straight-forward idea that comes to mind is to use two <include> layouts and hiding one of them in onCreateView() depending on variables. But I was wondering if there is a smarter approach.
Current layout xml:
The main content is inside the second FrameLayout and I'd like to have two versions to choose from.
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.MainActivity">
<ImageView
android:id="#+id/profile_monk_head_imageview"
android:layout_width="match_parent"
android:layout_height="200dp"
android:contentDescription="#string/profile_monk_image_content_desc"
android:src="#drawable/monk_head" />
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- This is what I want to switch out -->
<FrameLayout ... >
</androidx.core.widget.NestedScrollView>
</FrameLayout>
Use DataBindingUtil version inflate if layoutId is unknown in advance ( a.k.a dynamic binding). Otherwise, use the generated Binding's inflate method to ensure type-safe inflation.
Crosslink reference
I am trying to achieve like the image below how can i do in fragment android.libraries.places.widget i tried using relative layout but its not showing up inside the places widget can anyone suggest some good source to do it or is there any other layout which can be used to do it.
The Xml which i tried:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
tools:context=".Maps.MapsAddress" >
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_marginTop="10dp"
android:id="#+id/autocomplete_fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:name="com.google.android.libraries.places.
widget.AutocompleteSup portFragment"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Chetpet Chennai"
android:textSize="14sp"
android:id="#+id/toolbar_address">
</TextView>
</FrameLayout>
Root layout use : Relative
SearchBar layout can use searchview or floating searchview(external libraries)
Device Location can use relative layout so icon place at the start of parent and etc
Saved addresses you can use table layout.
Assign id to the different layout so that you can stack the layout inside of the root-relative layout
I need to hide the visibility of my layout but because it's an included layout with the merge tag I'm not being able to do it. I'm using kotlin and keep getting a null pointer exception when trying to hide the view by using
layout_bookings_past.visibility = View.GONE
with this import
import kotlinx.android.synthetic.main.layout_bookings_past.*
but tried also with
import kotlinx.android.synthetic.main.fragment_bookings.*
That's my code:
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include
android:id="#+id/layout_bookings_past"
layout="#layout/layout_bookings_past" />
</android.support.constraint.ConstraintLayout>
And for the merge layout I have something like:
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
Thanks very much.
Ps: I've a sample app that simulates the structure of my project here
When you use <merge> tag, merged views are actually merged right into parent ConstraintLayout, so ViewGroup with id layout_bookings_past doesn't exist.
To make sure you can check your layout in Layout Inspector:
You can notice, that tv_past and rv_past are childs of ConstraintLayout that is root layout of FragmentBookings.
The solution would be to add actual ViewGroup instead of <merge> like this:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
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">
<TextView
android:id="#+id/tv_past"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Past bookings"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/ll_buttons" />
<android.support.v7.widget.RecyclerView
android:id="#+id/rv_past"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="4dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/tv_past"
tools:itemCount="2"/>
</android.support.constraint.ConstraintLayout>
There's another option, if we assume, that we always include this layout to ConstraintLayout. You can add android.support.constraint.Group (more info) as a child of <merge> and reference it in your code. Like this:
<android.support.constraint.Group
android:id="#+id/merged_layout"
android:layout_width="0dp"
android:layout_height="0dp"
app:constraint_referenced_ids="tv_past,rv_past"/>
And just reference it as usually:
merged_layout.visibility = View.GONE
But I guess it is just easier to add ConstraintLayout as parent of the layout. Getting rid of redundant layouts is good, but not worth it in that case.
I have a custom view CustomSettingEntry this is its xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/layout_custom_setting_entry_container"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/custom_setting_entry_title"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
</LinearLayout>
Then I use it in a fragment and assign it an id:
<com.mypackage.name.CustomSettingEntry
android:id="#+id/layout_notification_setting"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:setting_title="#string/title"
app:setting_subtitle="#string/subtitle" />
My question is what's the difference between the LinearLayout with id layout_custom_setting_entry_container and the usage with id layout_notification_setting? do they refer to the same thing?
If I set a click listener on the custom view inside the fragment, then later in some condition disabled clicking on the root LinearLayout inside the custom view, will this stop the listener?
I understand your custom view is a subclass of LinearLayout which inflates an xml layout. If so, the resulting view hierarchy is
[LinearLayout (actually a CustomSettingEntry), id : layout_notification_setting]
[LinearLayout, id : layout_custom_setting_entry_container]
...
So there are two levels of viewgroups, each one with it own id.
By the way this is inefficient because, the outer viewgroup (your custom class) has only one child (the root of the xml).
On solution is to use a <merge> as root of the xml layout to skip one level. See Optimize by merging or Inflating layout for your custom view
for more details.