More media layout optimizations
This commit is contained in:
parent
e873dd7d0a
commit
cf4604e0d8
|
@ -14,22 +14,23 @@ public class PhotoLayoutHelper{
|
|||
public static final int MAX_WIDTH=1000;
|
||||
public static final int MAX_HEIGHT=1777; // 9:16
|
||||
public static final int MIN_HEIGHT=563;
|
||||
public static final float GAP=1.5f;
|
||||
|
||||
@NonNull
|
||||
public static TiledLayoutResult processThumbs(List<Attachment> thumbs){
|
||||
int _maxW=MAX_WIDTH;
|
||||
int _maxH=MAX_HEIGHT;
|
||||
float maxRatio=MAX_WIDTH/(float)MAX_HEIGHT;
|
||||
|
||||
TiledLayoutResult result=new TiledLayoutResult();
|
||||
if(thumbs.size()==1){
|
||||
Attachment att=thumbs.get(0);
|
||||
result.rowSizes=result.columnSizes=new int[]{1};
|
||||
if(att.getWidth()>att.getHeight()){
|
||||
result.width=_maxW;
|
||||
result.height=Math.max(MIN_HEIGHT, Math.round(att.getHeight()/(float)att.getWidth()*_maxW));
|
||||
float ratio=att.getWidth()/(float) att.getHeight();
|
||||
if(ratio>maxRatio){
|
||||
result.width=MAX_WIDTH;
|
||||
result.height=Math.max(MIN_HEIGHT, Math.round(att.getHeight()/(float)att.getWidth()*MAX_WIDTH));
|
||||
}else{
|
||||
result.height=_maxH;
|
||||
result.width=Math.round(att.getWidth()/(float)att.getHeight()*_maxH);
|
||||
result.height=MAX_HEIGHT;
|
||||
result.width=MAX_WIDTH;//Math.round(att.getWidth()/(float)att.getHeight()*MAX_HEIGHT);
|
||||
}
|
||||
result.tiles=new TiledLayoutResult.Tile[]{new TiledLayoutResult.Tile(1, 1, result.width, result.height, 0, 0)};
|
||||
return result;
|
||||
|
@ -38,7 +39,7 @@ public class PhotoLayoutHelper{
|
|||
}
|
||||
|
||||
String orients="";
|
||||
ArrayList<Float> ratios=new ArrayList<Float>();
|
||||
ArrayList<Float> ratios=new ArrayList<>();
|
||||
int cnt=thumbs.size();
|
||||
|
||||
|
||||
|
@ -51,44 +52,38 @@ public class PhotoLayoutHelper{
|
|||
|
||||
float avgRatio=!ratios.isEmpty() ? sum(ratios)/ratios.size() : 1.0f;
|
||||
|
||||
float maxW, maxH, marginW=0, marginH=0;
|
||||
maxW=_maxW;
|
||||
maxH=_maxH;
|
||||
|
||||
float maxRatio=maxW/maxH;
|
||||
|
||||
if(cnt==2){
|
||||
if(orients.equals("ww") && avgRatio>1.4*maxRatio && (ratios.get(1)-ratios.get(0))<0.2){ // two wide photos, one above the other
|
||||
float h=Math.max(Math.min(maxW/ratios.get(0), Math.min(maxW/ratios.get(1), (maxH-marginH)/2.0f)), MIN_HEIGHT/2f);
|
||||
float h=Math.max(Math.min(MAX_WIDTH/ratios.get(0), Math.min(MAX_WIDTH/ratios.get(1), (MAX_HEIGHT-GAP)/2.0f)), MIN_HEIGHT/2f);
|
||||
|
||||
result.width=Math.round(maxW);
|
||||
result.height=Math.round(h*2+marginH);
|
||||
result.width=MAX_WIDTH;
|
||||
result.height=Math.round(h*2+GAP);
|
||||
result.columnSizes=new int[]{result.width};
|
||||
result.rowSizes=new int[]{Math.round(h), Math.round(h)};
|
||||
result.tiles=new TiledLayoutResult.Tile[]{
|
||||
new TiledLayoutResult.Tile(1, 1, maxW, h, 0, 0),
|
||||
new TiledLayoutResult.Tile(1, 1, maxW, h, 0, 1)
|
||||
new TiledLayoutResult.Tile(1, 1, MAX_WIDTH, h, 0, 0),
|
||||
new TiledLayoutResult.Tile(1, 1, MAX_WIDTH, h, 0, 1)
|
||||
};
|
||||
}else if(orients.equals("ww") || orients.equals("qq")){ // next to each other, same ratio
|
||||
float w=((maxW-marginW)/2);
|
||||
float h=Math.max(Math.min(w/ratios.get(0), Math.min(w/ratios.get(1), maxH)), MIN_HEIGHT);
|
||||
float w=((MAX_WIDTH-GAP)/2);
|
||||
float h=Math.max(Math.min(w/ratios.get(0), Math.min(w/ratios.get(1), MAX_HEIGHT)), MIN_HEIGHT);
|
||||
|
||||
result.width=Math.round(maxW);
|
||||
result.width=MAX_WIDTH;
|
||||
result.height=Math.round(h);
|
||||
result.columnSizes=new int[]{Math.round(w), _maxW-Math.round(w)};
|
||||
result.columnSizes=new int[]{Math.round(w), MAX_WIDTH-Math.round(w)};
|
||||
result.rowSizes=new int[]{Math.round(h)};
|
||||
result.tiles=new TiledLayoutResult.Tile[]{
|
||||
new TiledLayoutResult.Tile(1, 1, w, h, 0, 0),
|
||||
new TiledLayoutResult.Tile(1, 1, w, h, 1, 0)
|
||||
};
|
||||
}else{ // next to each other, different ratios
|
||||
float w0=((maxW-marginW)/ratios.get(1)/(1/ratios.get(0)+1/ratios.get(1)));
|
||||
float w1=(maxW-w0-marginW);
|
||||
float h=Math.max(Math.min(maxH, Math.min(w0/ratios.get(0), w1/ratios.get(1))), MIN_HEIGHT);
|
||||
float w0=((MAX_WIDTH-GAP)/ratios.get(1)/(1/ratios.get(0)+1/ratios.get(1)));
|
||||
float w1=(MAX_WIDTH-w0-GAP);
|
||||
float h=Math.max(Math.min(MAX_HEIGHT, Math.min(w0/ratios.get(0), w1/ratios.get(1))), MIN_HEIGHT);
|
||||
|
||||
result.columnSizes=new int[]{Math.round(w0), Math.round(w1)};
|
||||
result.rowSizes=new int[]{Math.round(h)};
|
||||
result.width=Math.round(w0+w1+marginW);
|
||||
result.width=Math.round(w0+w1+GAP);
|
||||
result.height=Math.round(h);
|
||||
result.tiles=new TiledLayoutResult.Tile[]{
|
||||
new TiledLayoutResult.Tile(1, 1, w0, h, 0, 0),
|
||||
|
@ -97,74 +92,76 @@ public class PhotoLayoutHelper{
|
|||
}
|
||||
}else if(cnt==3){
|
||||
if((ratios.get(0) > 1.2 * maxRatio || avgRatio > 1.5 * maxRatio) || orients.equals("www")){ // 2nd and 3rd photos are on the next line
|
||||
float hCover=Math.min(maxW/ratios.get(0), (maxH-marginH)*0.66f);
|
||||
float w2=((maxW-marginW)/2);
|
||||
float h=Math.min(maxH-hCover-marginH, Math.min(w2/ratios.get(1), w2/ratios.get(2)));
|
||||
float hCover=Math.min(MAX_WIDTH/ratios.get(0), (MAX_HEIGHT-GAP)*0.66f);
|
||||
float w2=((MAX_WIDTH-GAP)/2);
|
||||
float h=Math.min(MAX_HEIGHT-hCover-GAP, Math.min(w2/ratios.get(1), w2/ratios.get(2)));
|
||||
if(hCover+h<MIN_HEIGHT){
|
||||
float prevTotalHeight=hCover+h;
|
||||
hCover=MIN_HEIGHT*(hCover/prevTotalHeight);
|
||||
h=MIN_HEIGHT*(h/prevTotalHeight);
|
||||
}
|
||||
result.width=Math.round(maxW);
|
||||
result.height=Math.round(hCover+h+marginH);
|
||||
result.columnSizes=new int[]{Math.round(w2), _maxW-Math.round(w2)};
|
||||
result.width=MAX_WIDTH;
|
||||
result.height=Math.round(hCover+h+GAP);
|
||||
result.columnSizes=new int[]{Math.round(w2), MAX_WIDTH-Math.round(w2)};
|
||||
result.rowSizes=new int[]{Math.round(hCover), Math.round(h)};
|
||||
result.tiles=new TiledLayoutResult.Tile[]{
|
||||
new TiledLayoutResult.Tile(2, 1, maxW, hCover, 0, 0),
|
||||
new TiledLayoutResult.Tile(2, 1, MAX_WIDTH, hCover, 0, 0),
|
||||
new TiledLayoutResult.Tile(1, 1, w2, h, 0, 1),
|
||||
new TiledLayoutResult.Tile(1, 1, w2, h, 1, 1)
|
||||
};
|
||||
}else{ // 2nd and 3rd photos are on the right part
|
||||
float wCover=Math.min(maxH*ratios.get(0), (maxW-marginW)*0.75f);
|
||||
float h1=(ratios.get(1)*(maxH-marginH)/(ratios.get(2)+ratios.get(1)));
|
||||
float h0=(maxH-h1-marginH);
|
||||
float w=Math.min(maxW-wCover-marginW, Math.min(h1*ratios.get(2), h0*ratios.get(1)));
|
||||
result.width=Math.round(wCover+w+marginW);
|
||||
result.height=Math.round(maxH);
|
||||
float height=Math.min(MAX_HEIGHT, MAX_WIDTH*0.66f/avgRatio);
|
||||
float wCover=Math.min(height*ratios.get(0), (MAX_WIDTH-GAP)*0.66f);
|
||||
float h1=(ratios.get(1)*(height-GAP)/(ratios.get(2)+ratios.get(1)));
|
||||
float h0=(height-h1-GAP);
|
||||
float w=Math.min(MAX_WIDTH-wCover-GAP, Math.min(h1*ratios.get(2), h0*ratios.get(1)));
|
||||
result.width=Math.round(wCover+w+GAP);
|
||||
result.height=Math.round(height);
|
||||
result.columnSizes=new int[]{Math.round(wCover), Math.round(w)};
|
||||
result.rowSizes=new int[]{Math.round(h0), Math.round(h1)};
|
||||
result.tiles=new TiledLayoutResult.Tile[]{
|
||||
new TiledLayoutResult.Tile(1, 2, wCover, maxH, 0, 0),
|
||||
new TiledLayoutResult.Tile(1, 2, wCover, height, 0, 0),
|
||||
new TiledLayoutResult.Tile(1, 1, w, h0, 1, 0),
|
||||
new TiledLayoutResult.Tile(1, 1, w, h1, 1, 1)
|
||||
};
|
||||
}
|
||||
}else if(cnt==4){
|
||||
if((ratios.get(0) > 1.2 * maxRatio || avgRatio > 1.5 * maxRatio) || orients.equals("wwww")){ // 2nd, 3rd and 4th photos are on the next line
|
||||
float hCover=Math.min(maxW/ratios.get(0), (maxH-marginH)*0.66f);
|
||||
float h=(maxW-2*marginW)/(ratios.get(1)+ratios.get(2)+ratios.get(3));
|
||||
float hCover=Math.min(MAX_WIDTH/ratios.get(0), (MAX_HEIGHT-GAP)*0.66f);
|
||||
float h=(MAX_WIDTH-2*GAP)/(ratios.get(1)+ratios.get(2)+ratios.get(3));
|
||||
float w0=h*ratios.get(1);
|
||||
float w1=h*ratios.get(2);
|
||||
float w2=h*ratios.get(3);
|
||||
h=Math.min(maxH-hCover-marginH, h);
|
||||
h=Math.min(MAX_HEIGHT-hCover-GAP, h);
|
||||
if(hCover+h<MIN_HEIGHT){
|
||||
float prevTotalHeight=hCover+h;
|
||||
hCover=MIN_HEIGHT*(hCover/prevTotalHeight);
|
||||
h=MIN_HEIGHT*(h/prevTotalHeight);
|
||||
}
|
||||
result.width=Math.round(maxW);
|
||||
result.height=Math.round(hCover+h+marginH);
|
||||
result.columnSizes=new int[]{Math.round(w0), Math.round(w1), _maxW-Math.round(w0)-Math.round(w1)};
|
||||
result.width=MAX_WIDTH;
|
||||
result.height=Math.round(hCover+h+GAP);
|
||||
result.columnSizes=new int[]{Math.round(w0), Math.round(w1), MAX_WIDTH-Math.round(w0)-Math.round(w1)};
|
||||
result.rowSizes=new int[]{Math.round(hCover), Math.round(h)};
|
||||
result.tiles=new TiledLayoutResult.Tile[]{
|
||||
new TiledLayoutResult.Tile(3, 1, maxW, hCover, 0, 0),
|
||||
new TiledLayoutResult.Tile(3, 1, MAX_WIDTH, hCover, 0, 0),
|
||||
new TiledLayoutResult.Tile(1, 1, w0, h, 0, 1),
|
||||
new TiledLayoutResult.Tile(1, 1, w1, h, 1, 1),
|
||||
new TiledLayoutResult.Tile(1, 1, w2, h, 2, 1),
|
||||
};
|
||||
}else{ // 2nd, 3rd and 4th photos are on the right part
|
||||
float wCover= Math.min(maxH*ratios.get(0), (maxW-marginW)*0.66f);
|
||||
float w=(maxH-2*marginH)/(1/ratios.get(1)+1/ratios.get(2)+1/ratios.get(3));
|
||||
float height=Math.min(MAX_HEIGHT, MAX_WIDTH*0.66f/avgRatio);
|
||||
float wCover= Math.min(height*ratios.get(0), (MAX_WIDTH-GAP)*0.66f);
|
||||
float w=(height-2*GAP)/(1/ratios.get(1)+1/ratios.get(2)+1/ratios.get(3));
|
||||
float h0=w/ratios.get(1);
|
||||
float h1=w/ratios.get(2);
|
||||
float h2=w/ratios.get(3)+marginH;
|
||||
w=Math.min(maxW-wCover-marginW, w);
|
||||
result.width=Math.round(wCover+marginW+w);
|
||||
result.height=Math.round(maxH);
|
||||
float h2=w/ratios.get(3)+GAP;
|
||||
w=Math.min(MAX_WIDTH-wCover-GAP, w);
|
||||
result.width=Math.round(wCover+GAP+w);
|
||||
result.height=Math.round(height);
|
||||
result.columnSizes=new int[]{Math.round(wCover), Math.round(w)};
|
||||
result.rowSizes=new int[]{Math.round(h0), Math.round(h1), Math.round(h2)};
|
||||
result.tiles=new TiledLayoutResult.Tile[]{
|
||||
new TiledLayoutResult.Tile(1, 3, wCover, maxH, 0, 0),
|
||||
new TiledLayoutResult.Tile(1, 3, wCover, height, 0, 0),
|
||||
new TiledLayoutResult.Tile(1, 1, w, h0, 1, 0),
|
||||
new TiledLayoutResult.Tile(1, 1, w, h1, 1, 1),
|
||||
new TiledLayoutResult.Tile(1, 1, w, h2, 1, 2),
|
||||
|
@ -185,14 +182,14 @@ public class PhotoLayoutHelper{
|
|||
HashMap<int[], float[]> tries=new HashMap<>();
|
||||
|
||||
// One line
|
||||
int firstLine, secondLine, thirdLine;
|
||||
tries.put(new int[]{firstLine=cnt}, new float[]{calculateMultiThumbsHeight(ratiosCropped, maxW, marginW)});
|
||||
int firstLine, secondLine;
|
||||
tries.put(new int[]{cnt}, new float[]{calculateMultiThumbsHeight(ratiosCropped, MAX_WIDTH, GAP)});
|
||||
|
||||
// Two lines
|
||||
for(firstLine=1; firstLine<=cnt-1; firstLine++){
|
||||
tries.put(new int[]{firstLine, secondLine=cnt-firstLine}, new float[]{
|
||||
calculateMultiThumbsHeight(ratiosCropped.subList(0, firstLine), maxW, marginW),
|
||||
calculateMultiThumbsHeight(ratiosCropped.subList(firstLine, ratiosCropped.size()), maxW, marginW)
|
||||
tries.put(new int[]{firstLine, cnt-firstLine}, new float[]{
|
||||
calculateMultiThumbsHeight(ratiosCropped.subList(0, firstLine), MAX_WIDTH, GAP),
|
||||
calculateMultiThumbsHeight(ratiosCropped.subList(firstLine, ratiosCropped.size()), MAX_WIDTH, GAP)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -200,23 +197,23 @@ public class PhotoLayoutHelper{
|
|||
// Three lines
|
||||
for(firstLine=1; firstLine<=cnt-2; firstLine++){
|
||||
for(secondLine=1; secondLine<=cnt-firstLine-1; secondLine++){
|
||||
tries.put(new int[]{firstLine, secondLine, thirdLine=cnt-firstLine-secondLine}, new float[]{
|
||||
calculateMultiThumbsHeight(ratiosCropped.subList(0, firstLine), maxW, marginW),
|
||||
calculateMultiThumbsHeight(ratiosCropped.subList(firstLine, firstLine+secondLine), maxW, marginW),
|
||||
calculateMultiThumbsHeight(ratiosCropped.subList(firstLine+secondLine, ratiosCropped.size()), maxW, marginW)
|
||||
tries.put(new int[]{firstLine, secondLine, cnt-firstLine-secondLine}, new float[]{
|
||||
calculateMultiThumbsHeight(ratiosCropped.subList(0, firstLine), MAX_WIDTH, GAP),
|
||||
calculateMultiThumbsHeight(ratiosCropped.subList(firstLine, firstLine+secondLine), MAX_WIDTH, GAP),
|
||||
calculateMultiThumbsHeight(ratiosCropped.subList(firstLine+secondLine, ratiosCropped.size()), MAX_WIDTH, GAP)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Looking for minimum difference between thumbs block height and maxH (may probably be little over)
|
||||
// Looking for minimum difference between thumbs block height and MAX_HEIGHT (may probably be little over)
|
||||
int[] optConf=null;
|
||||
float optDiff=0;
|
||||
for(int[] conf : tries.keySet()){
|
||||
float[] heights=tries.get(conf);
|
||||
float confH=marginH*(heights.length-1);
|
||||
float confH=GAP*(heights.length-1);
|
||||
for(float h : heights) confH+=h;
|
||||
float confDiff=Math.abs(confH-maxH);
|
||||
float confDiff=Math.abs(confH-MAX_HEIGHT);
|
||||
if(conf.length>1){
|
||||
if(conf[0]>conf[1] || conf.length>2 && conf[1]>conf[2]){
|
||||
confDiff*=1.1;
|
||||
|
@ -233,7 +230,7 @@ public class PhotoLayoutHelper{
|
|||
float[] optHeights=tries.get(optConf);
|
||||
int k=0;
|
||||
|
||||
result.width=Math.round(maxW);
|
||||
result.width=MAX_WIDTH;
|
||||
result.rowSizes=new int[optHeights.length];
|
||||
result.tiles=new TiledLayoutResult.Tile[thumbs.size()];
|
||||
float totalHeight=0f;
|
||||
|
@ -251,7 +248,7 @@ public class PhotoLayoutHelper{
|
|||
ArrayList<TiledLayoutResult.Tile> row=new ArrayList<>();
|
||||
for(int j=0; j<lineThumbs.size(); j++){
|
||||
float thumb_ratio=ratiosRemain.remove(0);
|
||||
float w=j==lineThumbs.size()-1 ? (maxW-totalWidth) : (thumb_ratio*lineHeight);
|
||||
float w=j==lineThumbs.size()-1 ? (MAX_WIDTH-totalWidth) : (thumb_ratio*lineHeight);
|
||||
totalWidth+=Math.round(w);
|
||||
if(j<lineThumbs.size()-1 && !gridLineOffsets.contains(totalWidth))
|
||||
gridLineOffsets.add(totalWidth);
|
||||
|
@ -263,7 +260,7 @@ public class PhotoLayoutHelper{
|
|||
rowTiles.add(row);
|
||||
}
|
||||
Collections.sort(gridLineOffsets);
|
||||
gridLineOffsets.add(Math.round(maxW));
|
||||
gridLineOffsets.add(Math.round(MAX_WIDTH));
|
||||
result.columnSizes=new int[gridLineOffsets.size()];
|
||||
result.columnSizes[0]=gridLineOffsets.get(0);
|
||||
for(int i=gridLineOffsets.size()-1; i>0; i--){
|
||||
|
@ -287,7 +284,7 @@ public class PhotoLayoutHelper{
|
|||
columnOffset+=tile.colSpan;
|
||||
}
|
||||
}
|
||||
result.height=Math.round(totalHeight+marginH*(optHeights.length-1));
|
||||
result.height=Math.round(totalHeight+GAP*(optHeights.length-1));
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
@ -16,7 +16,7 @@ public class MediaGridLayout extends ViewGroup{
|
|||
private static final String TAG="MediaGridLayout";
|
||||
|
||||
public static final int MAX_WIDTH=400; // dp
|
||||
private static final int GAP=1; // dp
|
||||
private static final int GAP=2; // dp
|
||||
private PhotoLayoutHelper.TiledLayoutResult tiledLayout;
|
||||
private int[] columnStarts=new int[10], columnEnds=new int[10], rowStarts=new int[10], rowEnds=new int[10];
|
||||
|
||||
|
@ -41,6 +41,9 @@ public class MediaGridLayout extends ViewGroup{
|
|||
}
|
||||
int width=Math.min(V.dp(MAX_WIDTH), MeasureSpec.getSize(widthMeasureSpec));
|
||||
int height=Math.round(width*(tiledLayout.height/(float)PhotoLayoutHelper.MAX_WIDTH));
|
||||
if(tiledLayout.width<PhotoLayoutHelper.MAX_WIDTH){
|
||||
width=Math.round(width*(tiledLayout.width/(float)PhotoLayoutHelper.MAX_WIDTH));
|
||||
}
|
||||
|
||||
int offset=0;
|
||||
for(int i=0;i<tiledLayout.columnSizes.length;i++){
|
||||
|
@ -78,6 +81,9 @@ public class MediaGridLayout extends ViewGroup{
|
|||
return;
|
||||
|
||||
int maxWidth=V.dp(MAX_WIDTH);
|
||||
if(tiledLayout.width<PhotoLayoutHelper.MAX_WIDTH){
|
||||
maxWidth=Math.round((r-l)*(tiledLayout.width/(float)PhotoLayoutHelper.MAX_WIDTH));
|
||||
}
|
||||
int xOffset=0;
|
||||
if(r-l>maxWidth){
|
||||
xOffset=(r-l)/2-maxWidth/2;
|
||||
|
|
Loading…
Reference in New Issue