Skip to content

Instantly share code, notes, and snippets.

@jasonqu
Last active August 29, 2015 14:26
Show Gist options
  • Save jasonqu/f10c553c47bb93c76904 to your computer and use it in GitHub Desktop.
Save jasonqu/f10c553c47bb93c76904 to your computer and use it in GitHub Desktop.
无水scala入群题 —— https://bitbucket.org/snippets/centaur/98qey
case class Size(width: Double, height: Double)
case class Point(x: Double, y: Double)
case class Row(origin: Point, children: List[Size], hSpacing: Double) {
lazy val widthWithSpacing = children.map(_.width + hSpacing).sum
lazy val maxHeight = children.map(_.height).max
lazy val getRectOrigins: Seq[Point] = {
children.foldRight(List[Point](origin)) { (curr, points) =>
points match {
case last :: rest =>
Point(last.x + curr.width + hSpacing, origin.y) ::
Point(last.x, origin.y + (maxHeight / 2) - (curr.height / 2)) :: rest
}
}.tail.reverse
}
}
object FlowLayout {
def layout(parentWidth: Double, padding: Double, vSpacing: Double, hSpacing: Double, children: Seq[Size]): Seq[Point] = {
children.foldLeft(List[Row]()) {(rows, curr) => rows match {
case Nil => Row(Point(padding, padding), List(curr), hSpacing) :: Nil
case row :: rest =>
if(row.widthWithSpacing + curr.width + 2 * padding <= parentWidth) {
Row(row.origin, curr :: row.children, hSpacing) :: rest
} else {
Row(Point(padding, row.origin.y + vSpacing + row.maxHeight), curr :: Nil, hSpacing) :: rows
}
}
}.reverse.flatMap(_.getRectOrigins)
}
}

在一个以左上角为原点(0.0, 0.0)的二维坐标系(这也是计算机显示设备常用的坐标系)中, 已知一个宽度(parentWidth)固定的矩形区域parent,指定它的内边距(padding,四个方向相同), 将一组子矩形在其中进行流式布局(Flow Layout):每一行从左至右排列,第一个子矩形左上角与parent左上角的水平距离为padding, 相邻子矩形之间的水平间距为hSpacing,如果加入下一个子矩形会导致宽度超出parentWidth,则此子矩形成为下一行的第一项 。每一行的高度由其中最高的子矩形确定,其它子矩形垂直居中。行与行之间的垂直间距为vSpacing。如图:

图示 图解

每一个矩形的宽高由 case class Size(width: Double, height: Double) 表示,点坐标由 case class Point(x: Double, y: Double) 表示。 请编写方法 def layout(parentWidth: Double, padding: Double, vSpacing: Double, hSpacing: Double, children: Seq[Size]): Seq[Point] 返回经过布局后所有子矩形的左上角坐标(以parent左上角为原点),需要保留次序。 可以美好假设每一个子矩形的宽度小于parentWidth - 2*padding,因此一定有解。

import org.scalatest._
import layout._
import layout.FlowLayout._
class Test extends FlatSpec with Matchers {
"Original test" should "be passed" in {
assert(layout(parentWidth = 10.0, padding = 0, vSpacing = 0, hSpacing = 0, Seq(Size(5, 7), Size(5, 5))) == Seq(Point(0.0, 0.0), Point(5.0, 1.0)))
assert(layout(parentWidth = 10.0, padding = 0, vSpacing = 3.0, hSpacing = 0, Seq(Size(5, 7), Size(5, 5))) == Seq(Point(0.0, 0.0), Point(5.0, 1.0)))
assert(layout(parentWidth = 10.0, padding = 0.0, vSpacing = 0, hSpacing = 1.0, Seq(Size(5, 7), Size(5, 5))) == Seq(Point(0.0, 0.0), Point(0.0, 7.0)))
assert(layout(parentWidth = 10.0, padding = 1.0, vSpacing = 0, hSpacing = 0, Seq(Size(5, 7), Size(5, 5))) == Seq(Point(1.0, 1.0), Point(1.0, 8.0)))
assert(layout(parentWidth = 10.0, padding = 1.0, vSpacing = 1.0, hSpacing = 0, Seq(Size(5, 7), Size(5, 5))) == Seq(Point(1.0, 1.0), Point(1.0, 9.0)))
assert(layout(parentWidth = 10.0, padding = 1.0, vSpacing = 1.0, hSpacing = 1.0, Seq(Size(5, 7), Size(5, 5))) == Seq(Point(1.0, 1.0), Point(1.0, 9.0)))
assert(layout(parentWidth = 10.0, padding = 1.0, vSpacing = 1.0, hSpacing = 0, Seq(Size(5, 7))) == Seq(Point(1.0, 1.0)))
assert(layout(parentWidth = 10.0, padding = 1.0, vSpacing = 1.0, hSpacing = 1.0, Seq()) == Seq())
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment