Appyx Interactions – UI representation¶
Overview¶
The UI representation translates the abstract model of the TransitionModel to visual properties.
The big picture is that you will define a set of animatable properties, such as:
@MutableUiStateSpecs
class TargetUiState(
val position: Position.Target,
val rotationZ: RotationZ.Target,
val backgroundColor: BackgroundColor.Target,
)
Then you will create instances of it to represent some key states an element can be in on the UI:
private val topLeftCorner = TargetUiState(
position = Position.Target(Alignment.TopStart),
rotationZ = RotationZ.Target(0f), // <-- +Rotation
backgroundColor = BackgroundColor.Target(Color(0xFFFFC629))
)
private val topRightCorner = TargetUiState(
position = Position.Target(Alignment.TopEnd),
rotationZ = RotationZ.Target(180f), // <-- +Rotation
backgroundColor = BackgroundColor.Target(Color(0xFF353535))
)
private val bottomRightCorner = TargetUiState(
position = Position.Target(Alignment.BottomEnd),
rotationZ = RotationZ.Target(270f), // <-- +Rotation
backgroundColor = BackgroundColor.Target(Color(0xFFFE9763))
)
private val bottomLeftCorner = TargetUiState(
position = Position.Target(Alignment.BottomStart),
rotationZ = RotationZ.Target(540f), // <-- +Rotation
backgroundColor = BackgroundColor.Target(Color(0xFF855353))
)
Finally, you will map all elements in your model state to instances of TargetUiState
. In our example there's only one element:
override fun TestDriveModel.State<InteractionTarget>.toUiTargets(): List<MatchedTargetUiState<InteractionTarget, TargetUiState>> =
listOf(
MatchedTargetUiState(element, elementState.toTargetUiState())
)
fun ElementState.toTargetUiState(): TargetUiState =
when (this) {
A -> uiStateA
B -> uiStateB
C -> uiStateC
D -> uiStateD
}
Doing so, Appyx will animate elements between these TargetUiStates
as the abstract model changes:
A more detailed view¶
Classes related to the UI representation:
MotionProperty
– defines an animatable UI propertyMotionProperty.Target
– defines a target value for its ownMotionProperty
TargetUiState
– a collection of differentMotionProperty.Target
values representing an element's desired representationMutableUiState
– mappable fromTargetUiState
, this class holds the transient state of animated values as they change between different targets
MotionProperty¶
Appyx comes with a set of classes derived from MotionProperty
. A non-exhaustive list of them:
Alpha
BackgroundColor
Position
RotationX
RotationY
RotationZ
Scale
ZIndex
- etc.
They represent UI properties that Appyx can animate. Their animated values will be automatically mapped to Compose Modifier
instances.
If you need a property that's not provided by Appyx, it should be very easy to create one (also consider submitting a PR).
Target values¶
A MotionProperty
is mutable towards target values. Target
specifies such a value. They're defined by each MotionProperty
, and are supposed to be immutable.
For example Alpha.Target
expects a Float
:
class Alpha /*...*/ {
class Target(
val value: Float,
/*...*/
) : MotionProperty.Target
}
While Position.Target
deals with Offset
:
class Position /*...*/ {
class Target(
val value: DpOffset,
/*...*/
) : MotionProperty.Target
}
TargetUiState¶
Create your TargetUiState
as the collection of MotionProperty.Target
properties that you want Appyx to animate. For example, if you only want cross-fade animation, you would only need Alpha
in your UI. Then you would define your TargetUiState
such as:
@MutableUiStateSpecs
class TargetUiState(
val alpha: Alpha.Target,
)
Or, as in the TestDrive
example, position, rotation, and color:
@MutableUiStateSpecs
class TargetUiState(
val position: Position.Target,
val rotation: Rotation.Target,
val backgroundColor: BackgroundColor.Target,
)
MutableUiState¶
You might have noticed that the above classes are annotated with @MutableUiStateSpecs
. Appyx comes with a KSP processor that will generate the corresponding MutableUiState
class for you, so that you don't have to.
Please refer to the KSP setup guide.
Observing MotionProperty in children UI¶
Sometimes children UI can depend on the transition animation values. Appyx provides an API to observe MotionProperty
inside children UI.
In this example, children composable retrieve and display DpOffset
value from Position
motion property as well as Float
value from RotationY
using this API:
// returns dpOffset value if transition has Position MotionProperty and null otherwise
val dpOffset : DpOffset? = motionPropertyRenderValue<Position.Value, Position>()?.offset
// returns rotationY value if transition has RotationY MotionProperty and null otherwise
val rotationY = motionPropertyRenderValue<Float, RotationY>()