如何布局“网格”屏幕中央的图像数量

发布于 2024-10-10 02:49:52 字数 1067 浏览 4 评论 0原文

我有一组 12 张图像要在布局中显示。该数字是半任意选择的,但纵向模式下水平方向为 3 个,垂直方向上为 4 个,横向方向则相反。

第一个实现是使用 gridview。问题是高度不能强制适应屏幕。 对于解决方法,我当然可以(尝试)缩放图像,但几乎不可能计算网格视图可用的房间:总屏幕尺寸当然是已知的,但您必须“猜测”通知栏的大小,而这并不“这似乎是一个优雅的解决方案。测量的尺寸并不真正可信:我没有在方向改变时完全重新启动(为了速度),但屏幕构建完整空间的方式在现场不可用。 最后的结论是,我不想计算图像的大小,然后相应地缩放它们:我认为最好说视图应该如何适合屏幕,对吧?

所以接下来的尝试就是使用 TableLayout。使用“ShrinkColumns=”*”图像拟合得很好,因此图像的大小现在就是我们想要的大小。但是我们在高度上可能拥有的“额外”空间现在在表格行之间均匀分配。这是可以预料的,但丑陋的是,

当前的代码似乎无关紧要,因为它不起作用,但最终看起来像这样: 我已经删除了所有填充和其他看起来不相关的东西。 (对于肖像:)

<TableLayout
       android:shrinkColumns="*">
    <TableRow>
        <ImageView/>
        <ImageView/>
        <ImageView/>
    </TableRow>
    … (repeat 3 tablerows)
</TableLayout>

为了“缩放”太大的图像,TableLayout 具有“shrinkcolumns=”*”” 属性。

我们怎样才能让三个ImageView在TableRow的中心对齐而不是在宽度上均匀分布呢?垂直列也是如此,我们如何才能将所有内容保持在一起而不分散到屏幕的整个高度上? 基本上,“多余”空间应该作为填充/边距位于两侧,现在它位于图像之间。

例子: 左边的屏幕截图显示了太多的左/右距离,右边的屏幕截图显示了太多的顶部/底部 example-androblip-layout-image

I have a set of 12 images to show in a layout. The number is chosen semi arbitrarily, but boils down to 3 horizontaly and 4 vertically for portrait mode and the other way around for landscape.

First implementation was using a gridview. Problem is the height cannot be forced to fit in the screen.
For a workaround I can (try to) scale the images ofcourse, but its near impossible to calculate the room available to the gridview: Total screensize is known ofcourse, but you have to 'guess' the size of the notification bar and that doesn't seem to be an elegant sollution. The measured size isn't really to be trusted: I'm not doing a complete restart on orientation change (for speed), but the way the screen is build the complete space isn't available on the spot.
In the end the conclusion is that I don't want to calculate the size of the images and then scale them accordingly: I think it's better to say how the views should fit in the screen, right?

So the next try is just using a TableLayout. Using "ShrinkColumns="*" the images fitted fine, so the size of the images is now how we want them. But 'extra' room we might have in the height is now evenly divided between the tablerows. This is to be expected, but ugly.

The current code seems irrelevant because it doesn’t work, but looks like this in the end:
I’ve removed all the padding and other stuff which doesnt seem relevant.
(for portait:)

<TableLayout
       android:shrinkColumns="*">
    <TableRow>
        <ImageView/>
        <ImageView/>
        <ImageView/>
    </TableRow>
    … (repeat 3 tablerows)
</TableLayout>

To ‘scale’ the too-large images, the TableLayout has the “shrinkcolumns=”*”” attribute.

How can we get the three ImageViews to be aligned in the center of the TableRow and not spread evenly in the width? And the same goes for the vertical columns, how can we keep everything together and not spread across the height of the screen?
Basically, the "excess" space should go to the sides as padding/margin, and now it goes in between the Images.

Example:
The left screen-shot shows too much left/right distance, the right has too much top/bottom
example-androblip-layout-image

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

梦里兽 2024-10-17 02:49:52

我认为使用自定义视图应该不会太难,这应该是一个有趣的练习。这是我的第一个自定义视图;欢迎反馈!

限制

  • AspectGrid 完全忽略其子级想要的大小。就您的目的而言,这似乎没问题。如果需要更高级的东西,onMeasure 需要做很多额外的工作。
  • 毫不犹豫地使用 AspectGrid 的父级建议的大小。这与上一个问题有关。

屏幕截图

横向屏幕截图 http://tinypic.com/images/404.gif

肖像截图

工作原理

主要参数是列数。行数是自动计算的,因为我们知道子项的数量。另一个主要参数是我们想要用于子项的长宽比(对于正方形设置为 1)。

在onLayout中,我们收到网格的最终大小,因此我们可以计算子项的最大宽度和高度。

然后我们根据纵横比检查这一点。如果孩子们太高,我们会让他们变矮(如肖像示例)。如果它们太宽,我们会使它们变窄(如风景示例中所示)。

这就是全部内容了;其余的只是管道。

代码

com/photogrid/AspectGrid.java:实际的 ViewGroup

package com.photogrid;

import android.content.Context;

public class AspectGrid extends ViewGroup {

    private int mNumColumns = 1;
    private int mHorizontalSpacing = 0;
    private int mVerticalSpacing = 0;
    private float mChildAspectRatio = 1.0f;

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

    public AspectGrid(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public AspectGrid(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        try {
            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AspectGrid);

            setNumColumns(a.getInt(R.styleable.AspectGrid_numColumns, mNumColumns));
            setHorizontalSpacing(a.getDimensionPixelSize(R.styleable.AspectGrid_horizontalSpacing, mHorizontalSpacing));
            setVerticalSpacing(a.getDimensionPixelSize(R.styleable.AspectGrid_verticalSpacing, mVerticalSpacing));
            setChildAspectRatio(a.getFloat(R.styleable.AspectGrid_childAspectRatio, mChildAspectRatio));

            a.recycle();
        } catch (RuntimeException ex) {
            throw ex;
        }
    }

    public int getNumColumns() {
        return mNumColumns;
    }

    public void setNumColumns(int numColumns) {
        if (numColumns < 1)
            throw new IllegalArgumentException("numColumns must be at least 1");
        if (numColumns != mNumColumns) {
            mNumColumns = numColumns;
            requestLayout();
        }
    }

    public int getHorizontalSpacing() {
        return mHorizontalSpacing;
    }

    public void setHorizontalSpacing(int horizontalSpacing) {
        mHorizontalSpacing = horizontalSpacing;
    }

    public int getVerticalSpacing() {
        return mVerticalSpacing;
    }

    public void setVerticalSpacing(int verticalSpacing) {
        mVerticalSpacing = verticalSpacing;
    }

    public float getChildAspectRatio() {
        return mChildAspectRatio;
    }

    public void setChildAspectRatio(float childAspectRatio) {
        if (childAspectRatio <= 0)
            throw new IllegalArgumentException("childAspectRatio must be positive");
        if (childAspectRatio != mChildAspectRatio) {
            mChildAspectRatio = childAspectRatio;
            requestLayout();
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int measuredWidth = widthSize;
        int measuredHeight = heightSize;
        int width = Math.max(measuredWidth, getSuggestedMinimumWidth());
        int height = Math.max(measuredHeight, getSuggestedMinimumHeight());
        setMeasuredDimension(width, height);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int childCount = getChildCount();
        if (childCount <= 0)
            return;

        int innerWidth = r - l - getPaddingLeft() - getPaddingRight();
        int innerHeight = b - t - getPaddingBottom() - getPaddingTop();
        int numRows = (childCount + mNumColumns - 1) / mNumColumns;

        int leftEdge = getPaddingLeft();
        int topEdge = getPaddingTop();
        int horizontalStride = (innerWidth + mHorizontalSpacing) / mNumColumns;
        int verticalStride = (innerHeight + mVerticalSpacing) / numRows;
        int childWidth = horizontalStride - mHorizontalSpacing;
        int childHeight = verticalStride - mVerticalSpacing;

        if (childHeight * mChildAspectRatio > childWidth) {
            childHeight = (int)(childWidth / mChildAspectRatio);
            verticalStride = childHeight + mVerticalSpacing;
            topEdge = (innerHeight + mVerticalSpacing - numRows * verticalStride) / 2; 
        } else {
            childWidth = (int)(childHeight * mChildAspectRatio);
            horizontalStride = childHeight + mHorizontalSpacing;
            leftEdge = (innerWidth + mHorizontalSpacing - mNumColumns * horizontalStride) / 2;
        }

        for (int i = 0; i < childCount; ++i) {
            View child = getChildAt(i);
            int row = i / mNumColumns;
            int column = i % mNumColumns;
            int left = leftEdge + column * horizontalStride;
            int top = topEdge + row * verticalStride;
            child.layout(
                left,
                top,
                left + childWidth,
                top + childHeight);
        }
    }

}

res/values/attrs.xml:在XML

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="AspectGrid">
        <attr name="numColumns" format="integer"/>
        <attr name="horizontalSpacing" format="dimension"/>
        <attr name="verticalSpacing" format="dimension"/>
        <attr name="childAspectRatio" format="float"/>
    </declare-styleable>
</resources>

res/layout/main.xml:上面屏幕截图中使用的示例

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res/com.photogrid"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    <com.photogrid.AspectGrid
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:padding="5dp"
        app:numColumns="3"
        app:horizontalSpacing="5dp"
        app:verticalSpacing="5dp"
        app:childAspectRatio="1.0"
        >
        <TextView  
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content"
            android:background="#ffcccc" 
            android:text="Item 1"
            />
        <TextView  
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content"
            android:background="#ccffcc" 
            android:text="Item 2"
            />
        <TextView  
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content"
            android:background="#ccccff" 
            android:text="Item 3"
            />
        <TextView  
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content"
            android:background="#ffffcc" 
            android:text="Item 4"
            />
        <TextView  
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content"
            android:background="#ffccff" 
            android:text="Item 5"
            />
        <TextView  
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content"
            android:background="#ccffff" 
            android:text="Item 6"
            />
    </com.photogrid.AspectGrid>
</LinearLayout>

I figured this shouldn't be too hard using a custom view, which should be an interesting exercise. This is my first custom view; feedback is welcome!

Limitations

  • AspectGrid completely ignores the size that its children want to be. For your purposes, this appears to be okay. If something fancier is needed, onMeasure needs a lot of extra work.
  • The size that is suggested by AspectGrid's parent is used without a second thought. This is related to the previous issue.

Screenshots

Landscape screenshot http://tinypic.com/images/404.gif

Portrait screenshot

How it works

A main parameter is the number of columns. The number of rows is computed automatically, because we know the number of children. Another main parameter is the aspect ratio we want to use for the children (set to 1 for squares).

In onLayout, we receive the final size of the grid, so we can compute the maximum width and height of the children.

We then check this against the aspect ratio. If the children are too tall, we make them shorter (as in the portrait example). If they are too wide, we make them narrower (as in the landscape example).

That's all there is to it; the rest is just plumbing.

The code

com/photogrid/AspectGrid.java: The actual ViewGroup class

package com.photogrid;

import android.content.Context;

public class AspectGrid extends ViewGroup {

    private int mNumColumns = 1;
    private int mHorizontalSpacing = 0;
    private int mVerticalSpacing = 0;
    private float mChildAspectRatio = 1.0f;

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

    public AspectGrid(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public AspectGrid(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        try {
            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AspectGrid);

            setNumColumns(a.getInt(R.styleable.AspectGrid_numColumns, mNumColumns));
            setHorizontalSpacing(a.getDimensionPixelSize(R.styleable.AspectGrid_horizontalSpacing, mHorizontalSpacing));
            setVerticalSpacing(a.getDimensionPixelSize(R.styleable.AspectGrid_verticalSpacing, mVerticalSpacing));
            setChildAspectRatio(a.getFloat(R.styleable.AspectGrid_childAspectRatio, mChildAspectRatio));

            a.recycle();
        } catch (RuntimeException ex) {
            throw ex;
        }
    }

    public int getNumColumns() {
        return mNumColumns;
    }

    public void setNumColumns(int numColumns) {
        if (numColumns < 1)
            throw new IllegalArgumentException("numColumns must be at least 1");
        if (numColumns != mNumColumns) {
            mNumColumns = numColumns;
            requestLayout();
        }
    }

    public int getHorizontalSpacing() {
        return mHorizontalSpacing;
    }

    public void setHorizontalSpacing(int horizontalSpacing) {
        mHorizontalSpacing = horizontalSpacing;
    }

    public int getVerticalSpacing() {
        return mVerticalSpacing;
    }

    public void setVerticalSpacing(int verticalSpacing) {
        mVerticalSpacing = verticalSpacing;
    }

    public float getChildAspectRatio() {
        return mChildAspectRatio;
    }

    public void setChildAspectRatio(float childAspectRatio) {
        if (childAspectRatio <= 0)
            throw new IllegalArgumentException("childAspectRatio must be positive");
        if (childAspectRatio != mChildAspectRatio) {
            mChildAspectRatio = childAspectRatio;
            requestLayout();
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int measuredWidth = widthSize;
        int measuredHeight = heightSize;
        int width = Math.max(measuredWidth, getSuggestedMinimumWidth());
        int height = Math.max(measuredHeight, getSuggestedMinimumHeight());
        setMeasuredDimension(width, height);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int childCount = getChildCount();
        if (childCount <= 0)
            return;

        int innerWidth = r - l - getPaddingLeft() - getPaddingRight();
        int innerHeight = b - t - getPaddingBottom() - getPaddingTop();
        int numRows = (childCount + mNumColumns - 1) / mNumColumns;

        int leftEdge = getPaddingLeft();
        int topEdge = getPaddingTop();
        int horizontalStride = (innerWidth + mHorizontalSpacing) / mNumColumns;
        int verticalStride = (innerHeight + mVerticalSpacing) / numRows;
        int childWidth = horizontalStride - mHorizontalSpacing;
        int childHeight = verticalStride - mVerticalSpacing;

        if (childHeight * mChildAspectRatio > childWidth) {
            childHeight = (int)(childWidth / mChildAspectRatio);
            verticalStride = childHeight + mVerticalSpacing;
            topEdge = (innerHeight + mVerticalSpacing - numRows * verticalStride) / 2; 
        } else {
            childWidth = (int)(childHeight * mChildAspectRatio);
            horizontalStride = childHeight + mHorizontalSpacing;
            leftEdge = (innerWidth + mHorizontalSpacing - mNumColumns * horizontalStride) / 2;
        }

        for (int i = 0; i < childCount; ++i) {
            View child = getChildAt(i);
            int row = i / mNumColumns;
            int column = i % mNumColumns;
            int left = leftEdge + column * horizontalStride;
            int top = topEdge + row * verticalStride;
            child.layout(
                left,
                top,
                left + childWidth,
                top + childHeight);
        }
    }

}

res/values/attrs.xml: Declaration of attributes for use in the XML

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="AspectGrid">
        <attr name="numColumns" format="integer"/>
        <attr name="horizontalSpacing" format="dimension"/>
        <attr name="verticalSpacing" format="dimension"/>
        <attr name="childAspectRatio" format="float"/>
    </declare-styleable>
</resources>

res/layout/main.xml: The example used in the screenshots above

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res/com.photogrid"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    <com.photogrid.AspectGrid
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:padding="5dp"
        app:numColumns="3"
        app:horizontalSpacing="5dp"
        app:verticalSpacing="5dp"
        app:childAspectRatio="1.0"
        >
        <TextView  
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content"
            android:background="#ffcccc" 
            android:text="Item 1"
            />
        <TextView  
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content"
            android:background="#ccffcc" 
            android:text="Item 2"
            />
        <TextView  
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content"
            android:background="#ccccff" 
            android:text="Item 3"
            />
        <TextView  
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content"
            android:background="#ffffcc" 
            android:text="Item 4"
            />
        <TextView  
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content"
            android:background="#ffccff" 
            android:text="Item 5"
            />
        <TextView  
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content"
            android:background="#ccffff" 
            android:text="Item 6"
            />
    </com.photogrid.AspectGrid>
</LinearLayout>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文