Android - Custom ViewGroup仅显示第一级子级

时间:2013-12-28 09:35:56

标签: android layout subview viewgroup invisible

我编写了一个自定义ViewGroup,以矩阵样式组织子视图(垂直和水平间隔相等)。但我有一个让我发疯的问题。视图组正确绘制了第一个级别的子级,但每个子视图都是不可见的。

这是布局代码

    <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:matrix="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <com.vincejin.timekiller.viewgroups.MatrixLayout
        android:id="@+id/matrix"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#efefef"
        matrix:ml_columns="2"
        matrix:ml_horizontal_space="5dp"
        matrix:ml_square="true"
        matrix:ml_vertical_space="5dp" >

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#628465" >

            <TextView
                android:id="@+id/txv_text"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/text_default" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#763965" >
        </LinearLayout>

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#872438" >
        </LinearLayout>
    </com.vincejin.timekiller.viewgroups.MatrixLayout>

</LinearLayout>

结果就是这个

http://i40.tinypic.com/256tsw1.png

正如您所看到的,第一个布局内部有一个textview但未显示...

以下是viewgroup的代码

代码:

package com.vincejin.timekiller.viewgroups;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;

import com.vincejin.timekiller.R;

public class MatrixLayout extends ViewGroup {
    private boolean square;
    private int columns ;
    private int horizontalSpace ;
    private int verticalSpace;
    private int cellHeight;
    private int cellWidth;

    public MatrixLayout(Context context) {
        super(context);
    }

    public MatrixLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray arr = context.obtainStyledAttributes(attrs, R.styleable.MatrixLayout);
        square = arr.getBoolean(R.styleable.MatrixLayout_ml_square,false);
        columns = arr.getInteger(R.styleable.MatrixLayout_ml_columns, 4);
        horizontalSpace = arr.getDimensionPixelSize(R.styleable.MatrixLayout_ml_horizontal_space, 3);
        verticalSpace = arr.getDimensionPixelSize(R.styleable.MatrixLayout_ml_vertical_space, 3);

        arr.recycle(); 
    }

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

    private void adjustChildren(int l, int t, int r, int b) {
        int count = getChildCount();
        int gone = 0;
        for (int i = 0; i < count; i++) {
            View currentChild = getChildAt(i);
            if (currentChild.getVisibility() == View.GONE) {
                gone++;
                return;
            }
            Rect currentCellPosition = calculatePositionOf(l,t,r,b,coordinatesFromIndex(i
                    - gone));
            currentChild.layout(
                    currentCellPosition.left,
                    currentCellPosition.top, 
                    currentCellPosition.right,
                    currentCellPosition.bottom);

        }

    }

    private Rect calculatePositionOf(int parentLeft, int parentTop, int parentRight, int parentBottom, int[] coordinates) {
        int row = coordinates[0];
        int col = coordinates[1];

        Rect result = new Rect();
        result.left = parentLeft + (col * (cellWidth + horizontalSpace));
        result.right =  result.left + cellWidth;
        result.top = parentTop + (row * (cellHeight + verticalSpace));
        result.bottom = result.top + cellHeight;
        return result;
    }

    private int[] coordinatesFromIndex(int index) {
        int[] result = new int[2];
        result[0] = index / columns;
        result[1] = index % columns;

        return result;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int w = MeasureSpec.getSize(widthMeasureSpec);
        int h = MeasureSpec.getSize(heightMeasureSpec);

        if (square) {
            w = Math.min(w, h);
            h = Math.min(w, h);
        } 

        // Cell size calculus
        int rows = getRowsCount();
        cellWidth = (w / (columns)) ;
        if(rows==0)
            cellHeight = 0;
        else
            cellHeight = (h/ rows) ;

        setMeasuredDimension(w, h);
    }

    private int getRowsCount() {
        int childCount = getChildCount();

        int gone = 0;
        for (int i = 0; i < childCount; i++)
            if (getChildAt(i).getVisibility() == View.GONE)
                gone++;
        if((childCount-gone)%columns==0)
            return (childCount - gone) / columns;
        return ((childCount - gone) / columns) + 1;

    }

    public boolean isSquare() {
        return square;
    }

    public void setSquare(boolean square) {
        this.square = square;
    }

    public int getColumns() {
        return columns;
    }

    public void setColumns(int columns) {
        this.columns = columns;
    }

}

这是可设置的

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MatrixLayout">
        <attr name="ml_columns" format="integer" />
        <attr name="ml_square" format="boolean" />
        <attr name="ml_vertical_space" format="dimension" />
        <attr name="ml_horizontal_space" format="dimension" />
    </declare-styleable>
</resources>

1 个答案:

答案 0 :(得分:0)

我在 pskink 的帮助下解决了。 有必要在onMeasure方法中测量每个子节点,所以我在方法的末尾添加了以下行。

cellWidthMeasure = MeasureSpec.makeMeasureSpec(cellWidth, MeasureSpec.EXACTLY);
cellHeightMeausure = MeasureSpec.makeMeasureSpec(cellHeight, MeasureSpec.EXACTLY);

int childCount = getChildCount();
for(int i=0;i<childCount;i++){
    View child= getChildAt(i);
    if(child.getVisibility()!=View.GONE)
    child.measure(cellWidthMeasure,cellHeightMeausure);
}