Search code examples
androidandroid-layoutandroid-fragmentsandroid-activityandroid-custom-view

android: custom view layout wrapping


I want to have two custom views like this:

class LoadingView extends RelativeLayout{
    //this view has a progressBar and can show and hide it.

    void setIsLoading(){
        // shows/hides progress bar
    }


    // some code ...
}

class OtherView extends LoadingView{
    //some code ...
}

LoadingView has a layout like this:

<RelativeLayout>
    <FrameLayout
        id="@+id/content">
        <!--this is where content goes-->
    </FrameLayout>

    <ProgressBar
        id="@+id/pb"/>
</RelativeLayout>

so that any custom view that inherits from it will be injected into FrameLayout

so if OtherView has it's own layout , it will be nested inside FrameLayout automatically and you will be able to call myOtherView.setIsLoading(true/false)

How would you suggest doing this ?


Solution

  • Keep a reference to the content FrameLayout when inflating the first view.

    public class LoadingView extends RelativeLayout {
    
        private ProgressBar progressBar;
        private FrameLayout contentFrame;
    
        public LoadingView(Context context) {
            super(context);
            initialize();
        }
    
        public LoadingView(Context context, AttributeSet attrs) {
            super(context, attrs);
            initialize();
        }
    
        public LoadingView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            initialize();
        }
    
        private void initialize() {
            View root = inflate(getContext(), R.layout.loading_view, this);
            progressBar = (ProgressBar) root.findViewById(R.id.progress_bar);
            contentFrame = (FrameLayout) root.findViewById(R.id.content_frame);
        }
    
        public void setLoading(boolean loading) {
            progressBar.setVisibility(loading ? VISIBLE : GONE);
        }
    
        protected FrameLayout getContentFrame() {
            return contentFrame;
        }
    
    }
    

    Then use getContentFrame as the parent view when inflating the child view.

    public class OtherView extends LoadingView {
    
        public OtherView(Context context) {
            super(context);
            initialize();
        }
    
        public OtherView(Context context, AttributeSet attrs) {
            super(context, attrs);
            initialize();
        }
    
        public OtherView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            initialize();
        }
    
        private void initialize() {
            View root = inflate(getContext(), R.layout.other_view, getContentFrame());
        }
    
    }
    

    loading_view.xml

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_height="match_parent"
        android:layout_width="match_parent">
    
        <FrameLayout
            android:id="@+id/content_frame"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    
        <ProgressBar
            android:id="@+id/progress_bar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    
    </RelativeLayout>
    

    other_view.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_height="match_parent"
        android:layout_width="match_parent"
        android:orientation="vertical">
    
        <TextView
            android:text="Title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
    
        <TextView
            android:text="Subtitle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
    
    </LinearLayout>
    

    And use it like this

    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_height="match_parent"
        android:layout_width="match_parent">
    
        <com.example.client.ui.OtherView
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    
    </FrameLayout>