2

I want to create a wrapper element that can be reusable throughout the whole app, because it's the base of each screen. This wrapper should be possible to add to layout editor in Android Studio and needs to be able to hold any inner elements inserted in editor. But these elements have to be inserted inside the layout under header with image and only inside a specified area defined in wrapper xml layout (innerContainer).

enter image description here

This is the layout of wrapper:

<ScrollView
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.support.constraint.ConstraintLayout
    ...
    android:background="@drawable/frame_container_layout"
    tools:context=...>

    <include
        android:id="@+id/cv_header"
        layout="@layout/cv_header"
        ...>
    </include>

    <android.support.constraint.ConstraintLayout
        android:id="@+id/innerContainer"
        .../>

</android.support.constraint.ConstraintLayout>

What I need is to use this layout in custom view in a way, that when it's used somewhere, the elements will be only inserted into innerContainer.

Child XML:

    <...custom_views.WrapperFragmentView
        ...
        app:exampleColor="#33b5e5"
        app:exampleDimension="24sp"
        app:exampleDrawable="@android:drawable/ic_menu_add"
        app:exampleString="Hello, WrapperFragmentView">


        <TextView
            android:id="@+id/textView1"
            ...
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"/>

    </...custom_views.WrapperFragmentView>

The child is now inserted over the wrapper layout, which is what I don't want. It's not inside innerContainer.

In kotlin file I defined

class WrapperFragmentView : android.support.constraint.ConstraintLayout {
...
    private fun init(attrs: AttributeSet?, defStyle: Int) {
        var inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
        inflater.inflate(R.layout.cv_wrapper_fragment, this, true)


        findViewById<android.support.constraint.ConstraintLayout>(R.id.innerContainer)

The innerContainer is the view I want to have as a root element for the children that are going to use it. Not the whole layout cv_wrapper_fragment.

How to set this in the WrapperFragmentView?

Or, if the whole concept is wrong and if there is an easier approach how to work with reusable wrapping elements I am all for that.

Tunerx
  • 619
  • 9
  • 21
  • You can override `addView(View, int, ViewGroup.LayoutParams)` in `WrapperFragmentView` to intercept the adding of children, and place them in the appropriate `ViewGroup`, like is shown in [my answer here](https://stackoverflow.com/a/36947869), and [here](https://stackoverflow.com/a/41059842). I have no idea how that'll work with Android Studio's graphical layout editor, though. – Mike M. Sep 28 '18 at 08:42
  • Thanks for the answer, it's exactly what I've been looking for. But not sure if I made something wrong, but addView is called before layout is inflated by constructor. Therefore the containerLayout is always null. When I just cancel addView then it's behaving like before. Just findViewById in addView is always null for me (I did findViewById in constructor like in example but it was the same). I did the steps from [this](https://stackoverflow.com/questions/36946173/android-custom-view-group-delegate-addview/36947869#36947869). – Tunerx Sep 28 '18 at 09:38
  • I'm not sure where you're calling your `init()` method, but `WrapperFragmentView`'s constructor will definitely be done before `addView()` is called. Are you sure `init()` is being called from the two-parameter constructor, the one that takes a `Context` and an `AttributeSet`? That's what `LayoutInflater` will use. I would also mention that it doesn't look like you're assigning the `findViewById<...>(R.id.innerContainer)` return to anything, so if that's how you're determining when the inner inflation is happening, maybe that's an issue? – Mike M. Sep 28 '18 at 09:47
  • I got it now. The problem was that the first addView run was adding Scrollview (the top element, that's why innerContainer was null - his parent didn't existed yet) and the 2nd run of addView added the textview I wanted inside. But this means I have to do the findViewById(R.id.innerContainer) inside addView (but just once anyway). Simple overview: `var innerContainer = findViewById(R.id.innerContainer) if(innerContainer == null) { super.addView(child, index, params) } else { innerContainer.addView(child, index, params) }`. – Tunerx Sep 28 '18 at 11:22

0 Answers0