//public int Opacity //{ // get // { // return PixelFormat.TRANSLUCENT; // } //} private void CanvasControlOnDraw(ICanvasAnimatedControl canvasControl, CanvasAnimatedDrawEventArgs args) { lock (this) { if (_bitmapCanvas == null) { return; } using (_bitmapCanvas.CreateSession(canvasControl.Device, canvasControl.Size.Width, canvasControl.Size.Height, args.DrawingSession)) { _bitmapCanvas.Clear(Colors.Transparent); LottieLog.BeginSection("Drawable.Draw"); if (_compositionLayer == null) { return; } var scale = _scale; float extraScale = 1f; float maxScale = GetMaxScale(_bitmapCanvas); if (scale > maxScale) { scale = maxScale; extraScale = _scale / scale; } if (extraScale > 1) { // This is a bit tricky... // We can't draw on a canvas larger than ViewConfiguration.get(context).getScaledMaximumDrawingCacheSize() // which works out to be roughly the size of the screen because Android can't generate a // bitmap large enough to render to. // As a result, we cap the scale such that it will never be wider/taller than the screen // and then only render in the top left corner of the canvas. We then use extraScale // to scale up the rest of the scale. However, since we rendered the animation to the top // left corner, we need to scale up and translate the canvas to zoom in on the top left // corner. _bitmapCanvas.Save(); float halfWidth = (float)_composition.Bounds.Width / 2f; float halfHeight = (float)_composition.Bounds.Height / 2f; float scaledHalfWidth = halfWidth * scale; float scaledHalfHeight = halfHeight * scale; _bitmapCanvas.Translate( Scale * halfWidth - scaledHalfWidth, Scale * halfHeight - scaledHalfHeight); _bitmapCanvas.Scale(extraScale, extraScale, scaledHalfWidth, scaledHalfHeight); } _matrix.Reset(); _matrix = MatrixExt.PreScale(_matrix, scale, scale); _compositionLayer.Draw(_bitmapCanvas, _matrix, _alpha); LottieLog.EndSection("Drawable.Draw"); if (extraScale > 1) { _bitmapCanvas.Restore(); } } } }
internal static void ApplyTrimPathIfNeeded(Path path, float startValue, float endValue, float offsetValue) { LottieLog.BeginSection("applyTrimPathIfNeeded"); PathMeasure.SetPath(path); var length = PathMeasure.Length; if (startValue == 1f && endValue == 0f) { LottieLog.EndSection("applyTrimPathIfNeeded"); return; } if (length == 0f || Math.Abs(endValue - startValue - 1) < .01) { LottieLog.EndSection("applyTrimPathIfNeeded"); return; } var start = length * startValue; var end = length * endValue; var newStart = Math.Min(start, end); var newEnd = Math.Max(start, end); var offset = offsetValue * length; newStart += offset; newEnd += offset; // If the trim path has rotated around the path, we need to shift it back. if (newStart >= length && newEnd >= length) { newStart = MiscUtils.FloorMod(newStart, length); newEnd = MiscUtils.FloorMod(newEnd, length); } if (newStart < 0) { newStart = MiscUtils.FloorMod(newStart, length); } if (newEnd < 0) { newEnd = MiscUtils.FloorMod(newEnd, length); } // If the start and end are equals, return an empty path. if (newStart == newEnd) { path.Reset(); LottieLog.EndSection("applyTrimPathIfNeeded"); return; } if (newStart >= newEnd) { newStart -= length; } _tempPath.Reset(); PathMeasure.GetSegment(newStart, newEnd, ref _tempPath, true); if (newEnd > length) { _tempPath2.Reset(); PathMeasure.GetSegment(0, newEnd % length, ref _tempPath2, true); _tempPath.AddPath(_tempPath2); } else if (newStart < 0) { _tempPath2.Reset(); PathMeasure.GetSegment(length + newStart, length, ref _tempPath2, true); _tempPath.AddPath(_tempPath2); } path.Set(_tempPath); LottieLog.EndSection("applyTrimPathIfNeeded"); }