Passing values to custom view in android

2019-06-24 07:20发布

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.

2条回答
ら.Afraid
2楼-- · 2019-06-24 07:32

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;
}
查看更多
在下西门庆
3楼-- · 2019-06-24 07:37

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.

查看更多
登录 后发表回答