【问题标题】:How is the height of a GridView determined, and can it be changed?GridView 的高度是如何确定的,可以改变吗?
【发布时间】:2013-09-10 07:05:11
【问题描述】:

我有一对垂直排列的 GridView,它们由适配器填充按钮。我可以让 GridView 填充父视图的宽度,但我无法让第二个 GridView 填充父视图的高度。

GridView 的高度似乎是固定的,无法更改。如果 GridView 有足够的空间,它们不会填充父级。如果没有足够的空间,它们会进入滚动模式——滚动模式无法关闭。

我不确定,但 GridView 似乎为子按钮视图使用了固定高度,我无法弄清楚按钮(行)高度是如何确定的,或者我如何更改它或强制 GridView填充父高度。

这是 GridViews 的 XML:

            <LinearLayout
                android:id="@+id/keypads"
                android:background="@color/keypad_background_color"
                android:layout_height="match_parent"
                android:layout_width="match_parent"
                android:isScrollContainer="false"
                android:orientation="vertical" >
            <GridView
                android:id="@+id/grdMeasButtons"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:numColumns="4"
                android:scrollbars="none"
                android:isScrollContainer="false"
                android:stretchMode="columnWidth" />

            <GridView
                android:id="@+id/grdNumButtons"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:numColumns="3"
                android:isScrollContainer="false"
                android:scrollbars="none"
                android:stretchMode="columnWidth" />
            </LinearLayout>

请注意,我的原始版本为每个 GridView 设置了 0px 的高度和 1:2 的权重比来设置 GridViews 的高度关系。这也不会填充父级,如果其中一个视图的权重太小,它就会进入滚动模式。 “isScrollContainer”属性不会关闭它。

这是来自适配器的 getView() 方法:

    // create a new ButtonView for each item referenced by the Adapter
public View getView(int position, View convertView, ViewGroup parent) {
    Button btn;
    if ((convertView == null) || !initializing) { // if it's not recycled, initialize some
                                // attributes

        btn = new Button(mContext);
        KeypadButton keypadButton = mButtons[position];

        switch(keypadButton.mCategory)
        {
        case NUMBER:
            btn.setBackgroundResource(R.drawable.keypadnumber);
            break;
        case DECIMAL:
            btn.setBackgroundResource(R.drawable.keypadnumber);
            break;
        case CLEAR:
            btn.setBackgroundResource(R.drawable.keypadnumber);
            break;
        case WEIGHT:    
        case VOLUME:
            switch (unitState[position]) {
            case SELECTED:
                btn.setEnabled(true);
                btn.setBackgroundResource(R.drawable.keypad_measure_selected);
                btn.setTextColor(mContext.getResources().getColor(R.color.units_text_enabled));
                break;
            case ENABLED:
                btn.setEnabled(true);
                btn.setBackgroundResource(R.drawable.keypad_measure_not_selected);
                btn.setTextColor(mContext.getResources().getColor(R.color.units_text_enabled));
                break;
            case DISABLED:
                btn.setEnabled(false);
                btn.setBackgroundResource(R.drawable.keypad_measure_not_selected);
                btn.setTextColor(mContext.getResources().getColor(R.color.units_text_disabled));
                break;
            default:
                break;
            }
            break;
        case DUMMY:
            break;
        default:
            btn.setBackgroundResource(R.drawable.keypadnumber);
            break;
        }
        // Set OnClickListener of the button to mOnButtonClick
        if(keypadButton != KeypadButton.DUMMY)
            btn.setOnClickListener(mOnButtonClick);
        else
            btn.setClickable(false);
        // Set CalculatorButton enumeration as tag of the button so that we
        // will use this information from our main view to identify what to do
        btn.setTag(keypadButton);
    } else {
        btn = (Button) convertView;
    }

    btn.setText(mButtons[position].getText());
    return btn;
}

(不用担心 unitState 数组。它解决了另一个问题。)

即使在视图被回收时,按钮的高度(和宽度)都为零,设置它没有任何效果。

GridView 或按钮的高度或填充属性可以在 GridView 填充之前在 Layout 参数中设置吗?

【问题讨论】:

    标签: android gridview


    【解决方案1】:
    // Just replace your second GridView With This One
    <GridView
            android:id="@+id/grdNumButtons"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:isScrollContainer="false"
            android:numColumns="3"
            android:scrollbars="none"
            android:stretchMode="columnWidth" />
    

    【讨论】:

    • 正如我所说,我的原始版本使用“0px”作为两个 GridView 的高度和权重,这没有任何区别——父级仍未填充。可以肯定的是,我尝试仅在第二个 GridView 上使用权重,但这也不起作用。
    【解决方案2】:

    如果 GridView 没有填充到父级,那么您必须在 getView() 方法中以编程方式计算设备高度。计算好设备高度后,将GridView的layoutParams设置为匹配父级或填充父级,即可解决您的问题。

    【讨论】:

    • 这种方法可以正确设置 GridView 的高度,但不会改变按钮的高度。因此,如果按钮没有足够的空间,GridView 就会滚动。有关解决方案,请参阅下面的帖子。
    【解决方案3】:

    pratik 提出的解决方案是正确的,但是在适配器中设置 GridView 的大小与在 XML 中对 GridView 使用“fill_parent”或加权高度没有什么不同。当然,GridView 设置为正确的高度,但按钮的大小始终相同。因此,如果 GridView 的按钮不够大,则 GridView 会滚动。对键盘没用。

    正如我所怀疑的,问题在于按钮的大小。我仍然不知道 Android 是如何确定按钮高度的,但它似乎是固定的——即,它不依赖于按钮宽度,它经过适当调整以适合 GridView 宽度。我猜这是GridView中的一个错误。在 GridView 中无法关闭滚动似乎也是一个错误。

    无论如何,解决方案是让每个 GridView 的适配器中的 getView() 将 button 高度设置为使它们完全适合分配给 GridView 的高度的值。我实际上在发布之前尝试过,但使用了构造:

    btn.setHeight(数字);

    而不是在按钮的布局参数中设置高度。那是因为我没有意识到按钮高度直到布局完成后才会设置。此外,我没有考虑获得可用的屏幕高度,因此我可以计算与设备无关的高度。很抱歉对这些东西不熟悉。

    我花了很多时间尝试使用包含 GridView 的 LinearLayout 的高度,这将减少我需要针对不同设备尺寸进行调整的常量数量。但是由于布局完成的时间和如何实现选项卡式片段的怪异,这变得非常混乱(是的,我尝试设置一个 OnGlobalLayoutListener)。最重要的是,这种方法存在一些时间问题。结果是键盘区域会消失一两秒钟,并在片段被破坏并重新创建后被选项卡进入视图时重新绘制。应该是可以的,但是我没时间弄明白。

    无论如何,这里是代码的相关补充。首先,我将在此处找到的以下方法添加到 MainActivity:

        // Method to get the usable screen height and width, which will then be available through their getters and setters
    
    private void setUsableScreenDimensions() {
        DisplayMetrics dm = getResources().getDisplayMetrics();
        float screen_w = dm.widthPixels;
        float screen_h = dm.heightPixels;
    
        int resId = getResources().getIdentifier("status_bar_height", "dimen", "android");
        if (resId > 0) {
            screen_h -= getResources().getDimensionPixelSize(resId);
        }
        TypedValue typedValue = new TypedValue();
        if(getTheme().resolveAttribute(android.R.attr.actionBarSize, typedValue, true)){
            screen_h -= getResources().getDimensionPixelSize(typedValue.resourceId);
        }       
        screenWidth = (double) screen_w;
        screenHeight = (double) screen_h;
    }
    

    然后我将这段代码添加到适配器构造函数中:

        double keypadParentHeight = (MainActivity.getScreenHeight() * Constants.KEYPAD_PARENT_HEIGHT_PERCENTAGE);
        double rowHeight = keypadParentHeight / Constants.NUMBER_OF_KEYPAD_ROWS;        
        buttonHeight = (int) (rowHeight * Constants.BUTTON_HEIGHT_FACTOR);
    

    最后这样设置getView中的按钮高度:

    LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, buttonHeight);
    LayoutParams params = params;
    

    实际代码稍微复杂一些,因为有两组不同权重(1:2)的键(两个GridView),所以按钮大小不同。此外,相同的小键盘由相同的适配器在三个不同大小的父LinearLayouts的不同片段上绘制。但这一切都归结为适配器中的一些额外常量和一些条件语句。

    【讨论】:

      猜你喜欢
      • 2017-02-16
      • 1970-01-01
      • 2011-10-15
      • 2019-09-22
      • 1970-01-01
      • 1970-01-01
      • 2010-10-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多