开发者

Custom Viewgroup works inside LinearLayout not RelativeLayout

开发者 https://www.devze.com 2023-04-10 16:36 出处:网络
I wanted to create a custom LinearLayout (and later a custom ImageButton) that could take percentage values for both dimensions of size based on its parent\'s size regardless of the parent type (Relat

I wanted to create a custom LinearLayout (and later a custom ImageButton) that could take percentage values for both dimensions of size based on its parent's size regardless of the parent type (Relative or Linear). I was following this post: How to size an Android view based on its parent's dimensions, and it was very helpful, but I have a problem that those answers don't address.

When I place my Custom LinearLayout inside another LinearLayout, everything works as expected. My Custom LinearLayout covers the expected space (80% of the parent's width in the example below).

However if I place it inside a RelativeLayout, my screen always shows empty, I am not sure why this happens.

Here is my class:

public class ButtonPanel extends LinearLayout {

    public ButtonPanel(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
        int parentHeight = 开发者_运维技巧MeasureSpec.getSize(heightMeasureSpec);

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        int newWidth = (int) Math.ceil(parentWidth * 0.8);

        this.setMeasuredDimension(newWidth, parentHeight);
        this.setLayoutParams(new RelativeLayout.LayoutParams(newWidth,parentHeight));

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
}

And here is my testing layout for the activity.

<RelativeLayout
      xmlns:android="http://schemas.android.com/apk/res/android"
      android:orientation="horizontal"
      android:layout_width="fill_parent"
      android:layout_height="fill_parent">

        <com.android.tests.views.ButtonPanel
            xmlns:android="http://schemas.android.com/apk/res/android"
            android:orientation="horizontal"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:background="@drawable/inner_panel"
                android:gravity="center_horizontal"
            android:layout_alignParentLeft="true"
            android:layout_alignParentTop="true">
        </com.android.tests.views.ButtonPanel>
    </RelativeLayout>

In my activity all I do is set the Content View to the above layout.

(Incidentally, does anybody now how I could get the type of the parent dynamically for setting the new LayoutParameters? Above you'll see the parent type (RelativeLayout) hard-coded into the Custom View onMeasure function)

Thanks in advance for any help!


Is this exposed to be a problem?

this.setLayoutParams(new RelativeLayout.LayoutParams(newWidth,parentHeight)); // <-- a RelativeLayout params?


In the onMeasure function you could use something like this to know what class is the parent of the view.

this.getParent().getClass().getName()

This should also work

a instanceof B

or

B.class.isAssignableFrom(a.getClass())

When using "instanceof", you need to know the class of "B" at compile time. When using "isAssignableFrom" it can be dynamic and change during runtime.

If you are not compfortable with string comparison, you could also use enums.


Turns out my two inquiries in this post were more related than expected.

I realized that by setting my view's LayoutParams to a completely new instance, I was overwriting the layout positioning information needed by the Relative Layout to position my view.

By 'zeroing out' that information, my view has the right dimensions, but the layout doesn't know where to place it, so it simply doesn't.

The following code for the new onMeasure shows how just directly modifying the height and width of the LayoutParams already attached to my view I avoid both overwriting the layout position information and having to create new LayoutParams based on the parent's type.

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        int specWidth = MeasureSpec.getSize(widthMeasureSpec);
        int specHeight = MeasureSpec.getSize(heightMeasureSpec);

        int newWidth = (int) Math.ceil(parentWidth * 0.8);
        int newHeight = (int) Math.ceil(parentHeight * 0.8);

        this.setMeasuredDimension(newWidth, newHeight);

        this.getLayoutParams().height = newHeight;
        this.getLayoutParams().width = newWidth;

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

Now, I'll be honest and say that this code is still not bug-free. Bringing the activity to the foreground and background multiple times constantly reduces the size of this custom view. The 0.8 reduction factor gets applied over and over each time the activity is brought up (I suspect the setting of the LayoutParams has to do with it, it might actually be unnecessary, but I haven't has time to test).

BUT, this still answered the question concerning this post, namely, why was my view not appearing at all despite having the right dimensions.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号