How to hide included merge layout - Kotlin null exception - android

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.

Related

Include layout file into constraint layout without affecting performance or Android Studio previews

I have a huge layout file with one flat constraint layout within.
I have android.support.constraint.Group elements that are identical. I want to move these to a separate file and then include them like <include layout="#layout/selection_group"/>
The problem I'm facing is that the group that I have in the file selection_group.xml is not previewed correctly in Android studio. Is there a way to make Android Studio preview this directly in the file or include them in a different way?
selection_group.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">
<android.support.constraint.Group
android:id="#+id/top_bar_config_one_background_group"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#drawable/top_bar_background_with_border_fx"
android:clickable="true"
app:constraint_referenced_ids="top_bar_config_one,top_bar_tooth_one"
app:layout_constraintBottom_toBottomOf="#+id/top_bar_container_background"
app:layout_constraintLeft_toLeftOf="#+id/top_bar_container_background"
app:layout_constraintRight_toLeftOf="#+id/top_bar_config_two"
app:layout_constraintTop_toTopOf="#+id/top_bar_container_background" />
<ImageView
android:id="#+id/top_bar_config_one"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false"
android:scaleType="center"
android:src="#drawable/ic_height_over_sea_100x26"
app:layout_constraintBottom_toTopOf="#+id/top_bar_tooth_one"
app:layout_constraintLeft_toLeftOf="#+id/top_bar_container_background"
app:layout_constraintRight_toLeftOf="#+id/top_bar_config_two"
app:layout_constraintTop_toTopOf="#+id/top_bar_config_one_background_group" />
<ImageView
android:id="#+id/top_bar_tooth_one"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="center"
android:src="#drawable/ic_tooth_auto_40x40"
app:layout_constraintBottom_toBottomOf="#+id/top_bar_config_one_background_group"
app:layout_constraintLeft_toLeftOf="#+id/top_bar_container_background"
app:layout_constraintRight_toLeftOf="#+id/top_bar_config_two" />
<?xml version="1.0" encoding="utf-8"?>
</layout>
I don't want to nest multiple constraint layouts together. I think the root <layout> view in selection_group.xml is optimized and does not affect the performance? My goal is to reduce redundant code and not affect performance
Try added a merge tag to the included layout:
<layout>
<merge>
<group>
... etc. ...
</merge>
</layout>
In order to make that layout file ready to be included you need to replace <layout> with <merge>
In case you need to use DataBinding into your layout you need to have <layout first and than <merge> tags on top of the layout file
I order to have proper preview in your inner layout which is going to be included - add on top level into merge tag:
tools:parentTag="ContraintLayout"
Something like this:
<merge 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"
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">

Change layout in 'Include' programmatically using Kotlin

I am writing a simple game and I'm wanting the main screen to have a choice of 3 layouts, for 2 handed, right handed or left handed.
I have an include for the controls. However I'm struggling to get the layout to change programatically. Been searching since last night but cannot find a way to do it, is it even possible?
<?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=".GamePlay">
<include
android:layout_width="match_parent"
android:layout_height="88dp"
layout="#layout/hand_two" <!-- this is what needs to change depending on settings -->
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:id="#+id/handLayout"/>
</androidx.constraintlayout.widget.ConstraintLayout>
From the animusmind's answer:
Use a ViewStub instead of include:
<ViewStub
android:id="#+id/layout_stub"
android:inflatedId="#+id/message_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="0.75" />
Then in code, get a reference to the stub, set its layout resource, and inflate it:
ViewStub stub = (ViewStub) findViewById(R.id.layout_stub);
stub.setLayoutResource(R.layout.whatever_layout_you_want);
View inflated = stub.inflate();
Answer collected from kcoppock
If you have multiple views which you would like to load them on demand programatically, ViewStub is one of the solution
please visit like link viewStub for multiple view

Layout inside another layout is not accessible from the activity

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

Android shared element transitions not working with <include> tag

I've been using shared element transitions in my app using ActivityOptionsCompat.makeSceneTransitionAnimation() and ActivityCompat.startActivityForResult() with some of the following XML code:
...
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:transitionName="#string/transition_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16sp"
android:paddingBottom="16sp">
...
</android.support.v7.widget.CardView>
...
Everything here works great.
However, since I am using the content inside my CardView multiple times, I decided to move it to a new layout and use <include> to reference it.
Here's the new layout file:
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
...
</android.support.v7.widget.CardView>
And the old file:
...
<include layout="#layout/my_card_content"
android:transitionName="#string/transition_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16sp"
android:paddingBottom="16sp" />
...
Now, for some reason, the shared element transitions don't seem to work.
How should I fix this issue?
Turns out the problem is because I need to include the android:transitionName inside the layout with my card so that my card layout looks like this:
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:transitionName="#string/transition_1"
android:layout_width="match_parent"
android:layout_height="wrap_content">
...
</android.support.v7.widget.CardView>
Meaning that it is not needed in my <include> tag:
<include layout="#layout/my_card_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16sp"
android:paddingBottom="16sp" />

import xml into another xml

I have lots of control repeated in my xml (a Button for instance). Is there any possibility to write the Button once in a xml and then import it in all the layout I need it?
You can use
<include layout="#layout/commonlayout" android:id="#+id/id" />
commonlayout.xml should be defined in res/layout where you can add the repeated parts.
As Labeeb P rightly said, it works.
Just want to add that you can also override parameters too:
<include
layout="#layout/commonlayout"
android:id="#+id/id"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginLeft="2sp"
android:layout_marginRight="2sp"
/>
In addition to those great answers, you can also avoid code duplication by using the <merge> tag, like so:
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/add"/>
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/delete"/>
</merge>
The <merge> part gets stripped when you include it into other xml. This might help including more than a single Button at a time. See the official documentation.
You can use the default include XML tag to include an external layout:
<include layout="#layout/somelayout" />
This layout should have an outside ViewGroup that encapsulates the content or a merge tag to avoid having to use an unnecessary layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="#string/hello_world" />
</LinearLayout>
<!-- OR -->
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<TextView android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="#string/hello_world" />
</merge>
Also, if you need a better way to include pieces of layout that acts like a container (a custom ViewGroup), you can use this custom ViewGroup. Note that this does not import an XML into another XML file, it inflates the content from the external layout and replaces into the view. It's similar to ViewStub, a "ViewGroupStub" like.
This lib acts as if the ViewStub could be used as following (note that this example does not work! ViewStub isn't a ViewGroup subclass!):
<ViewStub layout="#layout/somecontainerlayout"
inflate_inside="#+id/somecontainerid">
<TextView android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="#string/hello_world" />
</ViewStub>

Categories

Resources