4

Cheers,

I have an app that receives user input (2 numbers, width and height) and in theory depending on that input I have a custom view that should draw a grid (width and height).

Note:

  • These 2 values should be received before view attempts to draw itself.
  • These 2 values aren't constant and therefore I don't think XML approach can help.
  • I was told that adding another parameter to the View constructor is evil.
  • Do not confuse my 2 values with canvas.getWidth or etc.. these are values needed simply to draw something, nothing else.
  • My View is also a ViewGroup.
  • Main issue arises with Views declared in XML files.

I have temporarily solved this issue by making an SchemeContext class which contains those 2 static values and I simply set them in onCreate (before onCreateView) then use them in custom View onDraw when needed (SchemeContext.width). This is not really what people would call OOP I'm forcing global variables upon java and those are set on time because of the fragment lifecycle.

I've seen this answer How to pass variables to custom View before onDraw() is called?.

But it's more of a workaround than a solution (and probably not the fastest one). There has to be a sensible solution I don't think 3D games on android resort to these workarounds (SurfaceView with OpenGL is still a View right? :d).

If there is an obvious solution and this is an obvious double I'll remove the question.

14
  • What's wrong with having a method setValues(int width, int height) in your custom view? After assigning these values inside setValues(...), call invalidate()`. Commented Mar 11, 2015 at 0:42
  • Why is adding a constructor evil? If you don't want to do that then why not add set the values before adding the view to its container? Commented Mar 11, 2015 at 0:42
  • @Vikram Every object should be valid when its constructor returns. Commented Mar 11, 2015 at 0:46
  • vikram: because I think it's an extra pass through viewgroup tree. Perhaps it's nitpicking in small apps but I figure it could cause an issue down the road. Commented Mar 11, 2015 at 0:46
  • @KevinKrumwiede Please, do explain. Commented Mar 11, 2015 at 0:50

2 Answers 2

4

I haven't tried this, but I think it would be possible to do this fairly cleanly by overriding the LayoutInflater.Factory. That way, you can intercept the creation of the views that need additional parameters passed to their constructors, and let the rest of them fall through to default inflation.

For example, in your activity, before you inflate the view hierarchy:

LayoutInflater inflater = (LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE);
MyInflaterFactory factory = new MyInflaterFactory();
// Pass information needed for custom view inflation to factory.
factory.setCustomValue(42);
inflater.setFactory(factory);

For your implementation of the factory:

class MyInflaterFactory implements LayoutInflater.Factory {
    public void setCustomValue(int val) {
        mCustomVal = val;
    }

    @Override
    public View onCreateView (String name, Context context, AttributeSet attrs) {
        if (name.equals("com.package.ViewWithCustomCreation")) {
            return new ViewWithCustomCreation(context, attrs, mCustomVal);
        }
        return null;
    }

    private int mCustomVal;
}
Sign up to request clarification or add additional context in comments.

2 Comments

I shouldn't write this. But, its awesome o_o
Looks very interesting I'll try it then report hiw it went.
0

I was told that adding another parameter to the View constructor is evil.

Nonsense.

There are three (and in the newest APIs, four) different View constructors, each used in a different situation. (See this thread.) If you wanted to be able to declare your view in XML, for example, then you'd have to provide a constructor with exactly the right parameters, and have it call the corresponding superclass constructor. But there's nothing wrong with defining your own constructor (or even several of them) that call the superclass constructor intended for creating views programmatically.

The overriding principle is that every object must be valid when its constructor returns. So unless you can provide reasonable default values in your constructor, you have little choice but to accept the object's properties as constructor parameters.

6 Comments

I would likely agree with you for views that are created in java. But the issue for views or viewgroups declared in XML remains and I can't say declaring custom elements in XML should not be done because it's made possible.
@Spidey That answer fails to justify the rather bold claim that developers expect subclass constructors to have exactly the same parameters as superclass constructors. And I am talking about views created in code.
For java coded Views you are right. I still have issues with XML parts.
@Spidey I thought you said you couldn't use XML because the parameters come from the user at runtime. If you want to allow declaration in XML, you must provide a constructor that takes a Context, an AttributeSet, and nothing else. See this answer for how to create custom attributes.
My parameters do come from the user in runtime and my specific situation is that I made a custom viewgroup which I declared in XML to wrap it with DrawerLayout. Is that bad practice because I don't see why (other than the value passing inconvenience).
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.