在android中的屏幕上适应可变数量的视图

时间:2017-03-13 13:20:29

标签: android

我有一个可变数量的ImageViews,我想在线性布局中水平放置(有重叠)。我尝试了不同的解决方案,但每个解决方案要么调整图像大小,要么在图像重叠时使图像重叠(我希望图像只重叠以便为其他图像腾出空间)

我考虑的一个方面是动态调整保证金,但我不知道如何计算它。

提前谢谢大家

1 个答案:

答案 0 :(得分:1)

嗯,如果你自己在大小totalSize(水平/垂直的宽度/高度)的某个视图中的绝对位置绘制图像,这个类将计算第一个位置(水平/垂直的左/上) )。

你必须给它目标区域大小+所需方向的图像大小列表(它以通用方式书写,所以你可以水平或垂直使用它。)

例如,对于尺寸为100,200,100(总计400)的三个图像要适合区域310大,它将第一图像定位在0,第二图像定位在70(从右侧重叠第一图像的30个像素),并且第二个在240(第二个图像的重叠30个像素,并且在视图外部有30个像素)。所以每个图像都会有" cut"右侧30像素。

"加权"计算的变体将" cut"从右边按比例缩放到图像尺寸,所以在这种情况下返回的位置将是{0,77,232}隐藏那些图像右侧的23,45和22像素。

(如何将图像放在计算的位置上...可能AbsoluteLayoutFrameLayout将有助于分配区域,然后放置ImageView(或用于图像的内容)进入那个,并按计算的位置以编程方式定位)。

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class ImagePositioning {

    /**
     * Return possible positions for various images from the list, to fit into {@code totalSize}.
     * <p>
     * When overlapping is needed, image 0 is at bottom, and last image is reaching beyond {@code
     * totalSize} (should be cut by view draw), each next image overlapping the previous one.
     * <p>
     * When there's enough space for every image even with spare room, images are centered into
     * available spare space.
     *
     * @param totalSize
     *         Total size of available space (width for horizontal or height for vertical)
     * @param imageSizes
     *         Widths (or heights) of images to position.
     * @return List with starting position for images.
     */
    public static List<Integer> calculatePositions(
            final int totalSize, final List<Integer> imageSizes) {
        if (null == imageSizes || imageSizes.isEmpty()) return Collections.emptyList();
        final int imagesN = imageSizes.size();
        int imagesTotalSize = 0;
        for (int i = 0; i < imagesN; ++i) imagesTotalSize += imageSizes.get(i);
        double freeSpace = totalSize - imagesTotalSize, posX = 0.0;
        freeSpace /= imagesN;        // free space per image (unweighted)
        if (0 < freeSpace) posX = 0.5 * freeSpace;
        final List<Integer> r = new ArrayList<>(imagesN);
        for (int i = 0; i < imagesN; ++i) {
            r.add((int)posX);
            posX += freeSpace + imageSizes.get(i);
        }
        return r;
    }

    /**
     * Return possible positions for various images from the list, to fit into {@code totalSize}.
     * <p>
     * When overlapping is needed, image 0 is at bottom, and last image is reaching beyond {@code
     * totalSize} (should be cut by view draw), each next image overlapping the previous one.
     * <p>
     * When there's enough space for every image even with spare room, images are centered into
     * available spare space.
     * <p>
     * This method is different from {@link #calculatePositions(int, List)} by weighing the
     * spare/cut space per image by its own size, so larger images will get cut more than smaller
     * images.
     *
     * @param totalSize
     *         Total size of available space (width for horizontal or height for vertical)
     * @param imageSizes
     *         Widths (or heights) of images to position.
     * @return List with starting position for images.
     */
    public static List<Integer> calculateWeightedPositions(
            final int totalSize, final List<Integer> imageSizes) {
        if (null == imageSizes || imageSizes.isEmpty()) return Collections.emptyList();
        final int imagesN = imageSizes.size();
        int imagesTotalSize = 0;
        for (int i = 0; i < imagesN; ++i) imagesTotalSize += imageSizes.get(i);
        double freeSpace = totalSize - imagesTotalSize, posX = 0.0, totalInv = 1.0 / imagesTotalSize;
        final List<Integer> r = new ArrayList<>(imagesN);
        for (int i = 0; i < imagesN; ++i) {
            final Integer imageSize = imageSizes.get(i);
            // calculate weighted free space for this particular image
            double freeSpaceWeighted = freeSpace * imageSize * totalInv;
            if (0 < freeSpaceWeighted) r.add((int)(posX + 0.5 * freeSpaceWeighted));
            else r.add((int)posX);
            posX += freeSpaceWeighted + imageSize;
        }
        return r;
    }
}

JUnit4单元测试用于开发这个(TDD用来写这个,但我没有做最后一轮的重构测试,所以它有点不均匀分裂):

import junit.framework.Assert;

import org.junit.Test;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class ImagePositioningTest {

    ///////////////////////////////////////////////////////////////////////////
    // Fixed per-image positioning
    ///////////////////////////////////////////////////////////////////////////

    @Test
    public void nullList() throws Exception {
        final List<Integer> r = ImagePositioning.calculatePositions(0, null);
        Assert.assertNotNull(r);
        Assert.assertTrue(r.isEmpty());
    }

    @Test
    public void emptyList() throws Exception {
        List<Integer> list = Collections.emptyList();
        final List<Integer> r = ImagePositioning.calculatePositions(0, list);
        Assert.assertNotNull(r);
        Assert.assertTrue(r.isEmpty());
    }

    @Test
    public void singleImageFullWidth() throws Exception {
        List<Integer> list = Arrays.asList(500);
        final List<Integer> r = ImagePositioning.calculatePositions(500, list);
        Assert.assertNotNull(r);
        Assert.assertEquals(0, r.get(0).intValue());
    }

    @Test
    public void singleImageSmallerWidth() throws Exception {
        List<Integer> list = Arrays.asList(500);
        final List<Integer> r = ImagePositioning.calculatePositions(1000, list);
        Assert.assertNotNull(r);
        Assert.assertEquals(250, r.get(0).intValue());
    }

    @Test
    public void simpleWidths() throws Exception {
        List<Integer> listTwo = Arrays.asList(200, 200), r;

        r = ImagePositioning.calculatePositions(300, listTwo);
        Assert.assertNotNull(r);
        Assert.assertEquals(Arrays.asList(0, 150), r);

        r = ImagePositioning.calculatePositions(500, listTwo);
        Assert.assertNotNull(r);
        Assert.assertEquals(Arrays.asList(25, 275), r);

        List<Integer> listThree = Arrays.asList(100, 200, 100);

        r = ImagePositioning.calculatePositions(310, listThree);
        Assert.assertNotNull(r);
        Assert.assertEquals(Arrays.asList(0, 70, 240), r);

        r = ImagePositioning.calculatePositions(400, listThree);
        Assert.assertNotNull(r);
        Assert.assertEquals(Arrays.asList(0, 100, 300), r);

        r = ImagePositioning.calculatePositions(490, listThree);
        Assert.assertNotNull(r);
        Assert.assertEquals(Arrays.asList(15, 145, 375), r);
    }

    ///////////////////////////////////////////////////////////////////////////
    // Weighted positioning
    ///////////////////////////////////////////////////////////////////////////

    @Test
    public void wNullList() throws Exception {
        final List<Integer> r = ImagePositioning.calculateWeightedPositions(0, null);
        Assert.assertNotNull(r);
        Assert.assertTrue(r.isEmpty());
    }

    @Test
    public void wEmptyList() throws Exception {
        List<Integer> list = Collections.emptyList();
        final List<Integer> r = ImagePositioning.calculateWeightedPositions(0, list);
        Assert.assertNotNull(r);
        Assert.assertTrue(r.isEmpty());
    }

    @Test
    public void wSingleImageFullWidth() throws Exception {
        List<Integer> list = Arrays.asList(500);
        final List<Integer> r = ImagePositioning.calculateWeightedPositions(500, list);
        Assert.assertNotNull(r);
        Assert.assertEquals(0, r.get(0).intValue());
    }

    @Test
    public void wSingleImageSmallerWidth() throws Exception {
        List<Integer> list = Arrays.asList(500);
        final List<Integer> r = ImagePositioning.calculateWeightedPositions(1000, list);
        Assert.assertNotNull(r);
        Assert.assertEquals(250, r.get(0).intValue());
    }

    @Test
    public void wSimpleWidths() throws Exception {
        List<Integer> listTwo = Arrays.asList(200, 200), r;

        r = ImagePositioning.calculateWeightedPositions(300, listTwo);
        Assert.assertNotNull(r);
        Assert.assertEquals(Arrays.asList(0, 150), r);

        r = ImagePositioning.calculateWeightedPositions(500, listTwo);
        Assert.assertNotNull(r);
        Assert.assertEquals(Arrays.asList(25, 275), r);

        List<Integer> listThree = Arrays.asList(100, 200, 100);

        r = ImagePositioning.calculateWeightedPositions(310, listThree);
        Assert.assertNotNull(r);
        Assert.assertEquals(0, r.get(0), 2.0);
        Assert.assertEquals(310.0/400*100, r.get(1), 2.0);
        Assert.assertEquals(310.0/400*100 + 310.0/400*200, r.get(2), 2.0);

        r = ImagePositioning.calculateWeightedPositions(400, listThree);
        Assert.assertNotNull(r);
        Assert.assertEquals(Arrays.asList(0, 100, 300), r);

        r = ImagePositioning.calculateWeightedPositions(490, listThree);
        Assert.assertNotNull(r);
        Assert.assertEquals(Arrays.asList(11, 145, 378), r);
    }
}