我有一个可变数量的ImageViews,我想在线性布局中水平放置(有重叠)。我尝试了不同的解决方案,但每个解决方案要么调整图像大小,要么在图像重叠时使图像重叠(我希望图像只重叠以便为其他图像腾出空间)
我考虑的一个方面是动态调整保证金,但我不知道如何计算它。
提前谢谢大家
答案 0 :(得分:1)
嗯,如果你自己在大小totalSize
(水平/垂直的宽度/高度)的某个视图中的绝对位置绘制图像,这个类将计算第一个位置(水平/垂直的左/上) )。
你必须给它目标区域大小+所需方向的图像大小列表(它以通用方式书写,所以你可以水平或垂直使用它。)
例如,对于尺寸为100,200,100(总计400)的三个图像要适合区域310大,它将第一图像定位在0,第二图像定位在70(从右侧重叠第一图像的30个像素),并且第二个在240(第二个图像的重叠30个像素,并且在视图外部有30个像素)。所以每个图像都会有" cut"右侧30像素。
"加权"计算的变体将" cut"从右边按比例缩放到图像尺寸,所以在这种情况下返回的位置将是{0,77,232}隐藏那些图像右侧的23,45和22像素。
(如何将图像放在计算的位置上...可能AbsoluteLayout
或FrameLayout
将有助于分配区域,然后放置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);
}
}