Include layout with custom attributes

后端 未结 7 946
我寻月下人不归
我寻月下人不归 2020-12-02 22:24

I\'m building a complex layout and I want to use include tag for my custom component, like this:



        
7条回答
  •  南方客
    南方客 (楼主)
    2020-12-02 22:54

    I ran into this issue today. For whatever it is worth, I think there is a straight-forward work around. Instead of adding attributes to the include tag, create a custom wrapper view for the include and add attributes to that. Then, do the include from the wrapper. Have the wrapper class implementation extract the attributes and pass along to its single child, which is the root view of the include layout.

    So, say we declare some custom attributes for a wrapper called SingleSettingWrapper like this -

    
        
    
    

    Then, we create two custom view classes - one for the wrapper (SingleSettingWrapper) and one for the child (SingleSettingChild) that will be included -

    
    
    
        
        
    
    
    

    For the child, we can put whatever complex layout in there that we want. I'll just put something basic, but really you can include whatever -

    
        
            
            
            
        
    
    

    For the wrapper (this is the key), we read all of our custom attributes in the constructor. Then, we override onViewAdded() and pass those custom attributes to our child.

    public class SingleSettingWrapper extends FrameLayout 
    {
        private String mLabel;
    
        public SingleSettingWrapper(Context context, AttributeSet attrs)
        {
            super(context, attrs);
    
            TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
                                                                 R.styleable.SingleSettingWrapper,
                                                                 0, 0);
    
            mLabel = a.getString(R.styleable.SingleSettingWrapper_labelText);
            a.recycle();
        }
    
        public void onViewAdded(View child)
        {
            super.onViewAdded(child);
            if (!(child instanceof SingleSettingItem))
                return;
    
           ((TextView)child.findViewById(R.id.setting_single_label)).setText(mLabel);
            /*
            Or, alternatively, call a custom method on the child implementation -
            ((SingleSettingItem)child)setLabel(mLabel);
            */
        }
    }
    

    Optionally, you can implement the child too and have it receive messages from the wrapper and modify itself (instead of having the wrapper modify the child as I did above).

    public class SingleSettingItem extends LinearLayout
    {
        public SingleSettingItem(Context context, AttributeSet attrs)
        {
            super(context, attrs);
        }
    
        public void setLabel(String l)
        {
            // set the string into the resource here if desired, for example
        }
    }
    

    At the end of the day, each of the XML files where you wanted to your layout will contain about 7 lines of XML for the wrapper+include instead of the single include that you wanted, but if the included view contains hundreds of lines you're still way better off. For example -

    
    
        
        
            
        
        
    
    

    In practice, this seems to work pretty well and is relatively simple to set up. I hope it helps someone.

提交回复
热议问题