Android View Collisions

Base Solution

OnMeasure

override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
val fixedL = l + paddingLeft
val fixedT = t + paddingTop
val fixedR = r - paddingRight
val fixedB = b - paddingBottom

when(childCount) {
1 -> layoutOneChild(fixedL, fixedT, fixedR, fixedB)
2 -> layoutTwoChildren(fixedL, fixedT, fixedR, fixedB)
else -> layoutTreeChildren(fixedL, fixedT, fixedR, fixedB)
}
}
Animation of collapsing and expanding layout with 1, 2 and 3 children to see, how view deform their positions

👍Boost 1️⃣: Extrapolate it for any child count

Di is an distance between center of View_i element and View_(i + 1) element, except View1 (top) and View4 (bottom).

Concept of algorithm

  • a half of height of View_i (for View_1 it will be full height);
  • a half of height of View_(i+1) (for View_(n-1) it will be full height);
  • remained height
weight[i] = (view[i].height + view[i + 1].height) / 2
weight[0] = view[0].height + view[1].height / 2
weight[n - 2] = view[n - 2].height / 2 + view[n - 1].height
totalHeight = children.sum { it.height }
The freeHeight from the top is distributed between all elements of sortedWeights

Implementation

  1. Build array of weights:

Results

👍Boost 2️⃣: Add offsets

left: we can do that, right: we can not do that yet

Concept

  1. Take all view layout param’s weights and transform them to scales
  2. Normalize scales
  3. Adapt all weights (as we counted them earlier) with given scales
  4. Distribute freeHeights between all weights properly applying scales
  5. Build a distances
  6. Build a layout

Implementation

private class Bucket(
val filled: Float,
val scales: Float,
val position: Int
)
  1. Get view’s weight and create scales:

Results

Afterwords

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store