0

How do I set values in my View programmatically that it can use in onCreate()? Attributes can only be set in XML and member values can only be set after the View is inflated (and onCreate() already called).

Do I need to call the View constructor and set member values before inflating it? Or is there a better way?

Barry Fruitman
  • 12,316
  • 13
  • 72
  • 135
  • 5
    It's not really clear what you're trying to achieve, here, or what exactly the restrictions are. Why can't you initialize the `View` per usual? That is, why can't you just inflate it, or instantiate it, and then immediately set its properties as needed? – Mike M. Jan 18 '18 at 04:31
  • @MikeM. I'm trying to inflate a View from XML and then set some attributes programmatically *before* onCreate() is called. Is that possible? – Barry Fruitman Jan 18 '18 at 21:59
  • 1
    Not really. Well, not particularly elegantly, anyway, as far as I can figure. Why must the attributes be set before `onCreate()`? That's basically where you're meant to get the UI set up before it's displayed. `View`s aren't actually measured and laid out until after `onCreate()` finishes. – Mike M. Jan 18 '18 at 23:16

1 Answers1

0

If you inflate the view using Context.getLayoutInflater().createView(), you can pass custom attributes to this view programatically, using the last parameter

EDIT

In order to use attributes both from the xml and programatically, you will have to implement a custom LayoutInflater. However, since

You can see an example of custom layout In Android Rec Library.

You can see an example of custom AttributeSet in this SO answer.

Custom AttriuteSet

If I combine all those answer, you will get what you want, but it will require some boilerplate code, since AttributeSet is not really suitable for adding params on the fly. So you will have to implement AttributeSet (which is an interface) that gets the original AttributeSet in the constructor, and wraps all its functionality, and return the correct values for the parameters you want to add programatically.

Then you will be able to do something like:

private static class MyLayoutInflater implements LayoutInflater.Factory {

        private LayoutInflater other;

        MyLayoutInflater(LayoutInflater other) {
            this.other = other;
        }

        @Override
        public View onCreateView(String name, Context context, AttributeSet attrs) {
            if (name.equals("MyView")) {
                attrs = MyAttributeSet(attrs);
            }
            try {
                return other.createView(name, "", attrs);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();

            }
        }
    }

    private static class MyAttributeSet implements AttributeSet {

        private AttributeSet other;

        MyAttributeSet(AttributeSet other) {
            this.other = other;
        }

        < More implementations ...>
    }

    @Override
    protected void onCreate(Bundle savedInstanceState){
        getLayoutInflater().setFactory(new MyLayoutInflater(getLayoutInflater());
        getLayoutInflater().inflate(...)
    }

It may work, but there is probably a better way to achieve what you want.

Add Custom Params

You can implement a custom layoutinflater that will set some parameters before returning the view, so those will be added before onCreate is called on the view. So it will be something like:

@Override
protected void onCreate(Bundle savedInstanceState){
    getLayoutInflater().setFactory(new LayoutInflater.Factory() {
        public View onCreateView(String name, Context context, AttributeSet attrs) {
            if (name.equals("MyView")) {
                View myView = myView(context, attrs); // To get properties from attrs
                myView.setCustomParams(SomeCustomParam);
                return myView;
            } else {
                return null;
            }
        }
    });
    getLayoutInflater().inflate(...)
}
ElyashivLavi
  • 1,681
  • 3
  • 22
  • 33