我的自定义视图仅在 onCreate 中添加时才会绘制

发布于 2024-10-01 13:51:55 字数 2191 浏览 7 评论 0原文

我制作了一个“GraphBar”自定义视图,它是一个 RelativeLayout,底部有一个 TextView,上面有一个高度不同的 ImageView。代码如下:

public class GraphBar extends RelativeLayout {

    private int mAvailHeight; // space for the bar (component minus label)
    private float mBarHeight; // 0.0-1.0 value

    public GraphBar(Context context) {
        this(context, null);
    }

    public GraphBar(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public GraphBar(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        LayoutInflater.from(context).inflate(R.layout.graphbar, this, true);
        setId(R.id.graphBar); // defined in <merge> but not assigned (?)
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mAvailHeight = getHeight()-findViewById(R.id.label).getHeight();
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);

        View bar2 = findViewById(R.id.smallBar);
        RelativeLayout.LayoutParams llp2 = (RelativeLayout.LayoutParams) bar2.getLayoutParams();
        llp2.height = Math.round((float)mAvailHeight * mBarHeight);
    }

    public void setBarHeight(float value, float max) {
        mBarHeight = value / max;
        findViewById(R.id.smallBar).requestLayout();
    }

    public void setLabel(CharSequence c) {
        ((TextView) findViewById(R.id.label)).setText(c);
    }
}

虽然添加这些 GraphBar 并在 onCreate() 中设置它们的高度效果很好,但如果我在 onClickSomething 上创建它们或在创建的条上再次调用 setBarHeight() ,查看更改的唯一方法是加载视图层次结构。 此处告诉我,这意味着我需要调用某个地方requestLayout()。除了修改 mBarHeight 之后,还能在哪里呢?有什么帮助吗?我到处都尝试过,也尝试了 invalidate()

谢谢你, Andrea

(如果您需要,我可以发布我进行测试的活动和 graphbar.xml)


我发现它可能是 一个错误。解决方法应该是再次调用 requestLayout()。我还是不明白在哪里可以打电话。

I made a "GraphBar" custom view that is a RelativeLayout with a TextView on the bottom and an ImageView, varying in height, above that. Here is the code:

public class GraphBar extends RelativeLayout {

    private int mAvailHeight; // space for the bar (component minus label)
    private float mBarHeight; // 0.0-1.0 value

    public GraphBar(Context context) {
        this(context, null);
    }

    public GraphBar(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public GraphBar(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        LayoutInflater.from(context).inflate(R.layout.graphbar, this, true);
        setId(R.id.graphBar); // defined in <merge> but not assigned (?)
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mAvailHeight = getHeight()-findViewById(R.id.label).getHeight();
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);

        View bar2 = findViewById(R.id.smallBar);
        RelativeLayout.LayoutParams llp2 = (RelativeLayout.LayoutParams) bar2.getLayoutParams();
        llp2.height = Math.round((float)mAvailHeight * mBarHeight);
    }

    public void setBarHeight(float value, float max) {
        mBarHeight = value / max;
        findViewById(R.id.smallBar).requestLayout();
    }

    public void setLabel(CharSequence c) {
        ((TextView) findViewById(R.id.label)).setText(c);
    }
}

While adding these GraphBars and setting their height in onCreate() works well, if I create them onClickSomething or call again setBarHeight() on the created bars, the only way to see changes is Load View Hierarchy. I've been told here that it means I need to call somewhere requestLayout(). Where else than after modifying mBarHeight? Any help? I tried everywhere, and with invalidate() too.

Thank you,
Andrea

(if you need I can post the activity with which i do my tests and the graphbar.xml)


I've found it's probably a bug. The workaround should be, again, calling requestLayout(). Still i don't understand where i can put the call.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

独﹏钓一江月 2024-10-08 13:51:55

我终于找到了再次调用 requestLayout() 的方法。我在构造函数中调用了 setWillNotDraw(false) ,以便在 onDraw() (即 onLayout() 之后)中我可以调用额外的 <代码> requestLayout() 。这会产生一个愚蠢的循环,但从美学上解决了问题。

如果有人知道更好的解决方案,请告诉我...这里是新代码(修改位于注释旁边):

//...
    public GraphBar(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        LayoutInflater.from(context).inflate(R.layout.graphbar, this, true);
        setWillNotDraw(false); // WORKAROUND: onDraw will be used to make the
                                // redundant requestLayout() call
        setId(R.id.graphBar);
    }
//...
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        // i think it's one of the worst workaround one could think of.
        // luckily android is smart enough to stop the cycle...
        findViewById(R.id.smallBar).requestLayout();
    }

    public void setBarHeight(float value, float max) {
        mBarHeight = value / max;
        View bar =   findViewById(R.id.smallBar);

        bar.requestLayout(); // because when we create this view onDraw is called...
        bar.invalidate();    // ...but not when we modify it!!!
                            //so we need to invalidate too
    }
//...

I've finally found a way to call again requestLayout(). I called setWillNotDraw(false) in the constructor so that in onDraw() (that is after onLayout()) I can call the extra requestLayout(). This generates a stupid cycle but solves the problem aesthetically.

If anyone knows a better solution, let me know... here the new code (modifies are next to comments):

//...
    public GraphBar(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        LayoutInflater.from(context).inflate(R.layout.graphbar, this, true);
        setWillNotDraw(false); // WORKAROUND: onDraw will be used to make the
                                // redundant requestLayout() call
        setId(R.id.graphBar);
    }
//...
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        // i think it's one of the worst workaround one could think of.
        // luckily android is smart enough to stop the cycle...
        findViewById(R.id.smallBar).requestLayout();
    }

    public void setBarHeight(float value, float max) {
        mBarHeight = value / max;
        View bar =   findViewById(R.id.smallBar);

        bar.requestLayout(); // because when we create this view onDraw is called...
        bar.invalidate();    // ...but not when we modify it!!!
                            //so we need to invalidate too
    }
//...
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文