Flex 布局

感谢 @Winter 同学的支持,现在SpriteJS能够使用Flex布局了。

在Group上可以设置属性display: flex,开启flex布局。

布局 - FlexLayout - 图1

  1. ;(async function () {
  2. const scene = new Scene('#flex-basic', {viewport: ['auto', 'auto'], resolution: [1540, 600]});
  3. await scene.preload([
  4. 'https://p5.ssl.qhimg.com/t01f47a319aebf27174.png',
  5. 'https://s3.ssl.qhres.com/static/a6a7509c33a290a6.json',
  6. ]);
  7. const layer = scene.layer(),
  8. layout = new Group();
  9. layout.attr({
  10. display: 'flex',
  11. alignItems: 'flex-start',
  12. justifyContent: 'space-around',
  13. flexWrap: 'wrap',
  14. // size: [300, 500],
  15. width: 1200,
  16. pos: [770, 50],
  17. anchor: [0.5, 0],
  18. border: [6, '#aaa'],
  19. });
  20. layer.append(layout);
  21. const s1 = new Sprite('guanguan1.png'),
  22. s2 = new Sprite('guanguan2.png'),
  23. s3 = new Sprite('guanguan3.png'),
  24. s4 = new Sprite('guanguan3.png');
  25. s4.attr({
  26. anchor: 0.5,
  27. scale: [-1, 1],
  28. });
  29. layout.append(s1, s2, s3, s4);
  30. layout.animate([
  31. {width: 1200},
  32. {width: 400},
  33. ], {
  34. duration: 3000,
  35. direction: 'alternate',
  36. iterations: Infinity,
  37. });
  38. }())

容器属性

以下5个属性设置在容器上:

  • flexDirection
  • flexWrap
  • justifyContent
  • alignItems
  • alignContent

flexDirection

flexDirection属性决定主轴的方向(即项目的排列方向)。

flexDirection

它可能取4个值:

  • row(默认值):主轴为水平方向,起点在左端。
  • row-reverse:主轴为水平方向,起点在右端。
  • column:主轴为垂直方向,起点在上沿。
  • column-reverse:主轴为垂直方向,起点在下沿。

布局 - FlexLayout - 图3

  1. const scene = new Scene('#flex-direction', {viewport: ['auto', 'auto'], resolution: [1540, 600]});
  2. const layer = scene.layer();
  3. const s1 = new Sprite();
  4. s1.attr({
  5. size: [50, 50],
  6. bgcolor: 'red',
  7. });
  8. const s2 = s1.cloneNode();
  9. s2.attr({bgcolor: 'blue'});
  10. const s3 = s1.cloneNode();
  11. s3.attr({bgcolor: 'green'});
  12. const g1 = new Group();
  13. g1.attr({
  14. anchor: 0.5,
  15. pos: [200, 300],
  16. width: 200,
  17. bgcolor: 'grey',
  18. display: 'flex',
  19. flexDirection: 'row',
  20. });
  21. layer.append(g1);
  22. g1.append(s1, s2, s3);
  23. const g2 = g1.cloneNode();
  24. g2.attr({
  25. x: 500,
  26. flexDirection: 'row-reverse',
  27. });
  28. g2.append(...[s1, s2, s3].map(s => s.cloneNode()));
  29. layer.append(g2);
  30. const g3 = g1.cloneNode();
  31. g3.attr({
  32. x: 800,
  33. flexDirection: 'column',
  34. width: '',
  35. height: 200,
  36. });
  37. g3.append(...[s1, s2, s3].map(s => s.cloneNode()));
  38. layer.append(g3);
  39. const g4 = g1.cloneNode();
  40. g4.attr({
  41. x: 1100,
  42. flexDirection: 'column-reverse',
  43. width: '',
  44. height: 200,
  45. });
  46. g4.append(...[s1, s2, s3].map(s => s.cloneNode()));
  47. layer.append(g4);

flexWrap

默认情况下,项目都排在一条线(又称”轴线”)上。flexWrap属性定义,如果一条轴线排不下,如何换行。

flexWrap

它可能取3个值:

  • nowrap(默认值):不换行
  • wrap:换行,第一行在上方
  • wrap-reverse:换行,第一行在下方

布局 - FlexLayout - 图5

  1. const scene = new Scene('#flex-wrap', {viewport: ['auto', 'auto'], resolution: [1540, 600]});
  2. const layer = scene.layer();
  3. const s1 = new Sprite();
  4. s1.attr({
  5. size: [100, 100],
  6. bgcolor: 'red',
  7. });
  8. const s2 = s1.cloneNode();
  9. s2.attr({bgcolor: 'blue'});
  10. const s3 = s1.cloneNode();
  11. s3.attr({bgcolor: 'green'});
  12. const g1 = new Group();
  13. g1.attr({
  14. anchor: 0.5,
  15. pos: [300, 300],
  16. width: 200,
  17. bgcolor: 'grey',
  18. display: 'flex',
  19. flexDirection: 'row',
  20. flexWrap: 'nowrap',
  21. });
  22. layer.append(g1);
  23. g1.append(s1, s2, s3);
  24. const g2 = g1.cloneNode();
  25. g2.attr({
  26. x: 800,
  27. flexWrap: 'wrap',
  28. });
  29. g2.append(...[s1, s2, s3].map(s => s.cloneNode()));
  30. layer.append(g2);
  31. const g3 = g1.cloneNode();
  32. g3.attr({
  33. x: 1300,
  34. flexWrap: 'wrap-reverse',
  35. });
  36. g3.append(...[s1, s2, s3].map(s => s.cloneNode()));
  37. layer.append(g3);

justifyContent

justifyContent属性定义了项目在主轴上的对齐方式。

它可能取5个值,具体对齐方式与轴的方向有关。下面假设主轴为从左到右:

  • flex-start(默认值):左对齐
  • flex-end:右对齐
  • center: 居中
  • space-between:两端对齐,项目之间的间隔都相等。
  • space-around:每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。

布局 - FlexLayout - 图6

  1. const scene = new Scene('#flex-justify', {viewport: ['auto', 'auto'], resolution: [1540, 600]});
  2. const layer = scene.layer();
  3. const s1 = new Sprite();
  4. s1.attr({
  5. size: [50, 50],
  6. bgcolor: 'red',
  7. });
  8. const s2 = s1.cloneNode();
  9. s2.attr({bgcolor: 'blue'});
  10. const s3 = s1.cloneNode();
  11. s3.attr({bgcolor: 'green'});
  12. const g1 = new Group();
  13. g1.attr({
  14. anchor: 0.5,
  15. pos: [770, 100],
  16. width: 300,
  17. bgcolor: 'grey',
  18. display: 'flex',
  19. justifyContent: 'flex-start',
  20. });
  21. layer.append(g1);
  22. g1.append(s1, s2, s3);
  23. const g2 = g1.cloneNode();
  24. g2.attr({
  25. y: 200,
  26. justifyContent: 'flex-end',
  27. });
  28. g2.append(...[s1, s2, s3].map(s => s.cloneNode()));
  29. layer.append(g2);
  30. const g3 = g1.cloneNode();
  31. g3.attr({
  32. y: 300,
  33. justifyContent: 'center',
  34. });
  35. g3.append(...[s1, s2, s3].map(s => s.cloneNode()));
  36. layer.append(g3);
  37. const g4 = g1.cloneNode();
  38. g4.attr({
  39. y: 400,
  40. justifyContent: 'space-between',
  41. });
  42. g4.append(...[s1, s2, s3].map(s => s.cloneNode()));
  43. layer.append(g4);
  44. const g5 = g1.cloneNode();
  45. g5.attr({
  46. y: 500,
  47. justifyContent: 'space-around',
  48. });
  49. g5.append(...[s1, s2, s3].map(s => s.cloneNode()));
  50. layer.append(g5);

alignItems

alignItems属性定义项目在交叉轴上如何对齐。

它可能取4个值,具体的对齐方式与交叉轴的方向有关,下面假设交叉轴从上到下。

  • flex-start:交叉轴的起点对齐。
  • flex-end:交叉轴的终点对齐。
  • center:交叉轴的中点对齐。
  • stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度。

布局 - FlexLayout - 图7

  1. const scene = new Scene('#flex-alignItems', {viewport: ['auto', 'auto'], resolution: [1540, 600]});
  2. const layer = scene.layer();
  3. const s1 = new Sprite();
  4. s1.attr({
  5. size: [50, 100],
  6. bgcolor: 'red',
  7. });
  8. const s2 = s1.cloneNode();
  9. s2.attr({bgcolor: 'blue', height: 200});
  10. const s3 = new Label('中\n国');
  11. s3.attr({
  12. fillColor: 'cyan',
  13. font: '2rem "宋体"',
  14. bgcolor: 'green',
  15. });
  16. const g1 = new Group();
  17. g1.attr({
  18. anchor: 0.5,
  19. pos: [200, 300],
  20. width: 200,
  21. bgcolor: 'grey',
  22. display: 'flex',
  23. justifyContent: 'space-around',
  24. alignItems: 'flex-start',
  25. });
  26. layer.append(g1);
  27. g1.append(s1, s2, s3);
  28. const g2 = g1.cloneNode();
  29. g2.attr({
  30. x: 550,
  31. alignItems: 'flex-end',
  32. });
  33. g2.append(...[s1, s2, s3].map(s => s.cloneNode()));
  34. layer.append(g2);
  35. const g3 = g1.cloneNode();
  36. g3.attr({
  37. x: 900,
  38. alignItems: 'center',
  39. });
  40. g3.append(...[s1, s2, s3].map(s => s.cloneNode()));
  41. layer.append(g3);
  42. const g4 = g1.cloneNode();
  43. g4.attr({
  44. x: 1250,
  45. alignItems: 'stretch',
  46. });
  47. g4.append(...[s1, s2, s3].map(s => s.cloneNode()));
  48. layer.append(g4);

alignContent

alignContent属性定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。

该属性可能取6个值:

  • flex-start:与交叉轴的起点对齐。
  • flex-end:与交叉轴的终点对齐。
  • center:与交叉轴的中点对齐。
  • space-between:与交叉轴两端对齐,轴线之间的间隔平均分布。
  • space-around:每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍。
  • stretch(默认值):轴线占满整个交叉轴。

布局 - FlexLayout - 图8

  1. const scene = new Scene('#flex-alignContent', {viewport: ['auto', 'auto'], resolution: [1540, 600]});
  2. const layer = scene.layer();
  3. const s1 = new Sprite();
  4. s1.attr({
  5. size: [100, 100],
  6. bgcolor: 'red',
  7. });
  8. const s2 = s1.cloneNode();
  9. s2.attr({bgcolor: 'blue'});
  10. const s3 = s1.cloneNode();
  11. s3.attr({bgcolor: 'green'});
  12. const g1 = new Group();
  13. g1.attr({
  14. anchor: 0.5,
  15. pos: [200, 300],
  16. width: 200,
  17. height: 300,
  18. bgcolor: 'grey',
  19. display: 'flex',
  20. flexDirection: 'row',
  21. flexWrap: 'wrap',
  22. alignContent: 'stretch',
  23. });
  24. layer.append(g1);
  25. g1.append(s1, s2, s3);
  26. const g2 = g1.cloneNode();
  27. g2.attr({
  28. x: 500,
  29. alignContent: 'flex-start',
  30. });
  31. g2.append(...[s1, s2, s3].map(s => s.cloneNode()));
  32. layer.append(g2);
  33. const g3 = g1.cloneNode();
  34. g3.attr({
  35. x: 800,
  36. alignContent: 'flex-end',
  37. });
  38. g3.append(...[s1, s2, s3].map(s => s.cloneNode()));
  39. layer.append(g3);
  40. const g4 = g1.cloneNode();
  41. g4.attr({
  42. x: 1100,
  43. alignContent: 'space-between',
  44. });
  45. g4.append(...[s1, s2, s3].map(s => s.cloneNode()));
  46. layer.append(g4);
  47. const g5 = g1.cloneNode();
  48. g5.attr({
  49. x: 1400,
  50. alignContent: 'space-around',
  51. });
  52. g5.append(...[s1, s2, s3].map(s => s.cloneNode()));
  53. layer.append(g5);

元素属性

以下5个属性设置在元素上:

  • order:决定元素的排序方式
  • flexGrow:当元素被拉伸时,决定它被拉伸的比例
  • flexShrink:当元素被压缩时,决定它被压缩的比例
  • flexBasis:定义了在分配多余空间之前,项目占据的主轴空间(main size)。spritejs根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小。
  • alignSelf:覆盖容器的alignItems属性通过设置order来排序:

布局 - FlexLayout - 图9

  1. const scene = new Scene('#flex-order', {viewport: ['auto', 'auto'], resolution: [1540, 600]});
  2. const layer = scene.layer();
  3. const s1 = new Label('1');
  4. s1.attr({
  5. lineHeight: 100,
  6. fillColor: 'white',
  7. font: 'bold 2rem "宋体"',
  8. textAlign: 'center',
  9. size: [100, 100],
  10. bgcolor: 'red',
  11. });
  12. const s2 = s1.cloneNode();
  13. s2.attr({bgcolor: 'blue', text: '2'});
  14. const s3 = s1.cloneNode();
  15. s3.attr({bgcolor: 'green', text: '3'});
  16. const g1 = new Group();
  17. g1.attr({
  18. anchor: 0.5,
  19. pos: [300, 300],
  20. width: 200,
  21. bgcolor: 'grey',
  22. display: 'flex',
  23. flexDirection: 'row',
  24. flexWrap: 'wrap',
  25. });
  26. layer.append(g1);
  27. g1.append(s1, s2, s3);
  28. const g2 = g1.cloneNode();
  29. g2.attr({
  30. x: 800,
  31. });
  32. g2.append(...[s1, s2, s3].map((s, i) => s.cloneNode().attr({order: 2 - i})));
  33. layer.append(g2);
  34. const g3 = g1.cloneNode();
  35. g3.attr({
  36. x: 1300,
  37. });
  38. g3.append(...[s1, s2, s3].map((s, i) => s.cloneNode().attr({order: Math.abs(1 - i)})));
  39. layer.append(g3);

通过设置flex-grow来决定元素占据的空间:

布局 - FlexLayout - 图10

  1. const scene = new Scene('#flex-flex', {viewport: ['auto', 'auto'], resolution: [1540, 600]});
  2. const layer = scene.layer();
  3. const s1 = new Label('1');
  4. s1.attr({
  5. lineHeight: 100,
  6. fillColor: 'white',
  7. font: 'bold 2rem "宋体"',
  8. textAlign: 'center',
  9. size: [100, 100],
  10. bgcolor: 'red',
  11. flexGrow: 1,
  12. });
  13. const s2 = s1.cloneNode();
  14. s2.attr({bgcolor: 'blue', text: '2'});
  15. const s3 = s1.cloneNode();
  16. s3.attr({bgcolor: 'green', text: '3'});
  17. const g1 = new Group();
  18. g1.attr({
  19. anchor: 0.5,
  20. pos: [770, 150],
  21. width: 600,
  22. bgcolor: 'grey',
  23. display: 'flex',
  24. flexDirection: 'row',
  25. });
  26. layer.append(g1);
  27. g1.append(s1, s2, s3);
  28. const g2 = g1.cloneNode();
  29. g2.attr({
  30. y: 300,
  31. });
  32. g2.append(...[s1, s2, s3].map((s, i) => s.cloneNode().attr({flexGrow: i})));
  33. layer.append(g2);
  34. const g3 = g1.cloneNode();
  35. g3.attr({
  36. y: 450,
  37. });
  38. g3.append(...[s1, s2, s3].map((s, i) => s.cloneNode().attr({flexGrow: Math.abs(1 - i)})));
  39. layer.append(g3);