【问题标题】:How to make the contents of a custom view match its size when the parent has initial scale of 0?当父级的初始比例为 0 时,如何使自定义视图的内容与其大小匹配?
【发布时间】:2013-11-21 18:20:50
【问题描述】:

我正在开发一款 Android 游戏,但我有一个问题一直在尝试解决。

我有一个自定义视图,我已经覆盖了它的onDrawonMeasure。此自定义视图位于 LinearLayout 或 RelativeLayout 内,如下所示

<LinearLayout
    android:layout_width="0dip"
    android:layout_height="wrap_content"
    android:gravity="center_horizontal"
    android:layout_weight="2">

    <com.leftcorner.craftersofwar.images.BitmapView
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>

现在的问题是,在onMeasure 函数中,父级的大小为 0。我唯一能做的就是根据所需的内容大小缩放我的视图。但是,如果位图大于视图的最终尺寸,当我输入onDraw 函数时,这将导致画布错位。画布的 (0, 0) 坐标位于视图本身的边缘上方。

我可以在使用((View) this.getParent()).getWidth(); 绘制之前获取父尺寸,将位图尺寸与之比较并以正确的比例绘制位图,但将其绘制到画布上失败,因为位图超出了视图边界我不知道位置。

那么,我怎样才能将我的这个位图绘制到画布上以便它真正可见?如果它也在视图中居中会更好。

这是我目前拥有的代码:

@Override
protected void onDraw(Canvas canvas) {
    pWidth = ((View) this.getParent()).getWidth();
    pHeight = ((View) this.getParent()).getHeight();

    fWidth = Utility.smaller(pWidth, bWidth);
    fHeight = Utility.smaller(pHeight, bHeight);

    if(bitmap != null){
        // As you can see, I'm not using a custom bitmap class.
        // This function draws the bitmap to the canvas.
        // (x, y, width, height, canvas)
        bitmap.getStorageBitmap().drawScaledBitmap(0, 0, fWidth, fHeight, canvas);
    }
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    bWidth = Math.round(bitmap.getWidth() * scale);
    bHeight = Math.round(bitmap.getHeight() * scale);

    if(bitmap != null) setMeasuredDimension(bWidth, bHeight);
    else setMeasuredDimension(0, 0);
}

【问题讨论】:

    标签: android view bitmap android-canvas


    【解决方案1】:

    要获取父级的维度,您可以执行以下操作:

        // set the id of your LinearLayout to parentLayout
        LinearLayout parent = (LinearLayout)findViewById(R.id.parentLayout);
        final ViewTreeObserver observer = parent.getViewTreeObserver();
        observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
    
            @SuppressLint("NewApi")
            @SuppressWarnings("deprecation")
            @Override
            public void onGlobalLayout() {
    
                parent.measure(MeasureSpec.UNSPECIFIED,
                        MeasureSpec.UNSPECIFIED);
                int parentHeight = parent.getMeasuredHeight();
                int parentWidth = parent.getMeasuredWidth();
    
                // set dimensions to bitmap
                bitmap.getLayoutParams().height = parentHeight * scale;
                bitmap.getLayoutParams().width= parentWidth * scale;
                bitmap.requestLayout();
    
                ViewTreeObserver obs = parent.getViewTreeObserver();
    
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                    obs.removeOnGlobalLayoutListener(this);
                } else {
                    obs.removeGlobalOnLayoutListener(this);
                }
            }
        });
    

    你可以把这段代码直接放在onCreate中

    【讨论】:

    • 我多次使用自定义视图,因此函数必须在其中,这意味着我不能在 onCreate 中调用任何内容。此外,我已经提到我可以使用 ((View) this.getParent()).getWidth() 获取父尺寸,但即使在使用 getLayoutParams().width = pWidth; 调整视图大小之后也是如此。画布坐标似乎仍然很奇怪。
    • 如果使用RelativeLayout,问题仍然存在? (认为​​ LinearLayout 的权重可能会导致奇怪的行为)。另一种可能性是使用 FrameLayout 作为布局的根(不仅仅是位图的容器)。通过这种方式,您可以将位图直接添加到显示器上可能拥有的任何其他布局之上。
    • 你是对的。 LinearLayout 权重是有罪的,检查父级是否是 LinearLayout 的实例并不是什么大问题,所以我之前的论点是错误的。我很抱歉我没有考虑清楚。我即将以自己的方式解决这个问题。我的解决方案与您的解决方案有很大不同,但基本思想是相同的:发布布局大小计算。我在 onMeasure 中计算所有内容,在 onDraw 中检查宽度或高度是否接近 0。如果是,我将调用 requestLayout 而不是绘制位图。
    • 当我清除其中的小错误后,我会添加我自己的解决方案作为答案,但我会接受你的答案作为正确的答案,因为它基本上是正确的。
    • 我自己的解决方案如下。同样的事情以非常不同的方式完成。
    【解决方案2】:

    cYrixmorten 给出的答案是正确的,但我以不同的方式解决了这个问题。请注意,我的 LinearLayout 的高度设置为 wrap_content 但它的宽度来自权重。

    这是我的代码:

    @Override
    protected void onDraw(Canvas canvas) {
        if(getWidth() < 1 || getHeight() < 1){
            requestLayout();
        } else if(bitmap != null){
            bitmap.getStorageBitmap().drawScaledBitmap(0, 0, getWidth(), getHeight(), canvas);
        }
    }
    
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if(bitmap != null) {
            bitmapWidth = Math.round(bitmap.getWidth() * scale);
            bitmapHeight = Math.round(bitmap.getHeight() * scale);
        } else {
            setMeasuredDimension(0, 0);
            return;
        }
    
        parentWidth = MeasureSpec.getSize(widthMeasureSpec);
    
        if(parentWidth < bitmapWidth){
            bitmapHeight = bitmapHeight * parentWidth / bitmapWidth;
            bitmapWidth = parentWidth;
        }
    
        setMeasuredDimension(bitmapWidth, bitmapHeight);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-11-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-15
      • 2014-03-03
      相关资源
      最近更新 更多