更改布局和容器的自定义按钮大小

时间:2011-09-02 00:27:53

标签: android resize custom-view

我有一个扩展TextView类的自定义类(touchbutton)。我无法手动调整按钮大小。我可以让按钮只适用于一种类型的布局或容器,但不能同时使用两种。在大多数情况下,触摸按钮位于网格视图中,因此我更改大小的方法如下:

private void setLayout(buttonsize_t size) {

    log("Setting Layout: "+buttonsize_t.getPxl(size));

    final float scale = getContext().getResources().getDisplayMetrics().density;
    int dim = (int) (buttonsize_t.getPxl(size) * scale + 0.5f);

    AbsListView.LayoutParams params = (AbsListView.LayoutParams) getLayoutParams();
    if (params != null) {
        params.height = dim;
        params.width = dim;
    }
    else {
        params = new AbsListView.LayoutParams(dim,dim);
    }
    setLayoutParams(params);
}

然而,当在LinearLayout(例如)中调整TouchButton的大小时,我遇到了Logcat的崩溃:

09-01 19:18:35.630: ERROR/AndroidRuntime(20793): java.lang.ClassCastException: android.widget.LinearLayout$LayoutParams cannot be cast to android.widget.AbsListView$LayoutParams
09-01 19:18:35.630: ERROR/AndroidRuntime(20793):     at com.ians.aac3.TouchButton.setLayout(TouchButton.java:204)

第204行是指params的实例化。

我注意到GridViewLinearLayout共享父ViewGroup,所以我尝试使用ViewGroup.LayoutParams。但是,这将导致gridviews的相同行为(logcat引用相同的行)。

有谁知道我如何才能使这项工作适用于任何类型的布局或小工具?

更新: 按照建议,我再次尝试使用View组:

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.Log;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.TextView;
.....
ViewGroup.LayoutParams params = getLayoutParams();
        if (params != null) {
            params.height = dim;
            params.width = dim;
        }
        else {
            params = new LayoutParams(dim,dim);
        }
        setLayoutParams(params);

或者没有尝试回收当前的layoutparams:

setLayoutParams(new ViewGroup.LayoutParams(dim, dim));

我得到了同样的错误:

09-02 09:10:49.680: ERROR/AndroidRuntime(7069): java.lang.ClassCastException: android.view.ViewGroup$LayoutParams cannot be cast to android.widget.AbsListView$LayoutParams
09-02 09:10:49.680: ERROR/AndroidRuntime(7069):     at android.widget.GridView.onMeasure(GridView.java:1028)
09-02 09:10:49.680: ERROR/AndroidRuntime(7069):     at android.view.View.measure(View.java:10828)
09-02 09:10:49.680: ERROR/AndroidRuntime(7069):     at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4351)
09-02 09:10:49.680: ERROR/AndroidRuntime(7069):     at android.widget.FrameLayout.onMeasure(FrameLayout.java:267)
09-02 09:10:49.680: ERROR/AndroidRuntime(7069):     at android.view.View.measure(View.java:10828)
09-02 09:10:49.680: ERROR/AndroidRuntime(7069):     at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4351)
09-02 09:10:49.680: ERROR/AndroidRuntime(7069):     at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1284)

更新2: 似乎使用上面指定的ViewGroup.LayoutParams适用于LinearLayout。但是,如上所示,gridview不喜欢它......

2 个答案:

答案 0 :(得分:19)

要了解这里发生了什么,您需要查看Android源代码。 ViewGroup generateLayoutParams中有一个JavaDoc声明的方法:

  

根据提供的布局返回一组安全的布局参数   PARAMS。当ViewGroup传递一个其布局参数不具有的视图时   通过测试   checkLayoutParams(android.view.ViewGroup.LayoutParams),这种方法是   调用。此方法应返回一组适合的新布局参数   对于此ViewGroup,可能通过复制适当的属性   来自指定的布局参数集。

如果您查看LinearLayout和AbsListView(GridView的父级)源代码,您会看到他们将子级布局参数分别转换为LinearsLayout.LayoutParamsAbsListView.LayoutParams。但是,只有将子项添加到布局中时才会发生此转换 因此,如果您将TouchButton添加到LinearLayout(programmaticaly或通过XML),它将收到LinearsLayout.LayoutParams,如果您将其添加到GridView(通过适配器),它将收到AbsListView.LayoutParams
但是如果您之后手动设置布局参数,您将在父容器代码中的某处获得ClassCastException(因为它期望其子布局参数具有某种特定类型)。

为了解决您的问题,我建议您使用以下内容:

private void setLayout(buttonsize_t size) {

    log("Setting Layout: "+buttonsize_t.getPxl(size));

    final float scale = getContext().getResources().getDisplayMetrics().density;
    int dim = (int) (buttonsize_t.getPxl(size) * scale + 0.5f);

    ViewGroup.LayoutParams params = (ViewGroup.LayoutParams) getLayoutParams();
    if (params != null) {  
        params.height = dim;
        params.width = dim;
        setLayoutParams(params);
    } else {
      // the LayoutParams was not set yet, it must be the GridView 
      // which delays setting till child rendering
      params = new AbsListView.LayoutParams(dim, dim);
      setLayoutParams(params);
    }
}

答案 1 :(得分:0)

为什么要投射LayoutParams?

Button.getLayoutParams()应返回ViewGroup.LayoutParams,您可以访问高度和宽度 - 无需投射。你确定当你尝试ViewGroup.LayoutParams时没做过类似的事情吗?

ViewGroup.LayoutParams params = (AbsListView.LayoutParams) getLayoutParams();

(那仍然会失败)。

无论如何,请使用:

ViewGroup.LayoutParams params = getLayoutParams();

然后,如果你仍然得到一个例外,发布那个例外 - 而不是那个带有投射的那个。