Compound animations give you the ability to combine multiple animations as a storyboard. Let's replace the preceding function with our new implementation using a compound animation as follows:
private async Task AnimateFocalTarget(Point touchPoint) { _focalTarget.TintColorString = "#007F00"; var storyboard = new Animation(); var translationX = new Animation(callback: x => _focalTarget.TranslationX = x, start: touchPoint.X, end: touchPoint.X - (IMG_TARGET_BOUND / 2), easing: Easing.Linear); var translationY = new Animation(callback: y => _focalTarget.TranslationY = y, start: touchPoint.Y, end: touchPoint.Y - (IMG_TARGET_BOUND / 2), easing: Easing.Linear); var scaleFirst = new Animation(callback: o => _focalTarget.Scale = o, start: 0.5, end: 1, easing: Easing.Linear); var fade = new Animation(callback: o => _focalTarget.Opacity = o, start: 1, end: 0.7f, easing: Easing.Linear); var scaleSecond = new Animation(callback: o => _focalTarget.Scale = o, start: 1, end: 0.5f, easing: Easing.Linear); storyboard.Add(0, 0.01, translationX); storyboard.Add(0, 0.01, translationY); storyboard.Add(0, 0.01, scaleFirst); storyboard.Add(0, 0.5, fade); storyboard.Add(0.5, 1, scaleSecond); var tcs = new TaskCompletionSource<bool>(); storyboard.Commit(_focalTarget, "_focalTarget", length: 300, finished: async (arg1, arg2) => { _focalTarget.TintOn = true; await Task.Delay(500); _focalTarget.TintColorString = "#FFFFFF"; _isAnimating = false; tcs.TrySetResult(true); }); await tcs.Task; }
Each Animation
object has the property we are animating, a start point and an end point, and easing
(linear, bounce in, bounce out). All Animation
objects are then added to the storyboard. The first two parameters of the Add
function are the start time and finish time of that particular animation. Finally, we call the commit, and instead of awaiting the Commit
function, we will use a TaskCompletionSource
object to await the commit until it is finished. The finished
action is called after the length of 300 milliseconds.
Isn't that much nicer than our previous implementation?
We should use this approach when we have multiple animations to commit at any one time.
Now let's add the Reset
functions to our FocusView
. This will be called whenever an orientation has occurred, we will use the assign the focus point to the correct orientation starting point:
#region Public Methods public void Reset() { switch (Orientation) { case Orientation.Portrait: NotifyFocus(_pStartingOrientation); break; case Orientation.LandscapeLeft: case Orientation.LandscapeRight: NotifyFocus(_pFlippedOrientation); break; } }
The NotifyFocus
function is responsible for controlling the entire touch animation; this is where we will set the starting state of the _focalTarget
image, call the AddFocualTargetImg
function, and then fire the TouchFocus
event. This event will be used to focus the CameraView
through the custom renderer:
public void NotifyFocus(Point touchPoint) { if (_isAnimating) { return; } _focalTarget.Opacity = 0.0f; _focalTarget.TintOn = false; _isAnimating = true; Device.BeginInvokeOnMainThread(async () => await AnimateFocalTarget(touchPoint)); TouchFocus?.Invoke (this, touchPoint); }
Finally, we have the SetFocusPoints
function to assign the starting focus points in each orientation (landscape and portrait). These starting points will always be the center of the CameraView
. This is to ensure that the _focalTarget
image is centered inside the CameraView
on every change in orientation:
public void SetFocusPoints(Point pStart, Point pFlipped) { _pStartingOrientation = pStart; _pFlippedOrientation = pFlipped; } #endregion
That's everything for our FocusView
. Let's add our next custom UI element, the CameraView
.
3.15.237.123