Skip to content
This repository was archived by the owner on May 1, 2024. It is now read-only.

Commit

Permalink
[Android iOS Material] ActivityIndicator (#5088)
Browse files Browse the repository at this point in the history
* [Android iOS Material] ActivityIndicator

* address comments

* [iOS] background path optimization
  • Loading branch information
Pavel Yakovlev authored and PureWeen committed Jan 30, 2019
1 parent 629d482 commit b4d12ab
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 46 deletions.
56 changes: 31 additions & 25 deletions Xamarin.Forms.Material.iOS/MaterialActivityIndicatorRenderer.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.ComponentModel;
using CoreAnimation;
using CoreGraphics;
using MaterialComponents;
using UIKit;
Expand All @@ -13,6 +14,9 @@ public class MaterialActivityIndicatorRenderer : ViewRenderer<ActivityIndicator,
SemanticColorScheme _defaultColorScheme;
SemanticColorScheme _colorScheme;

CAShapeLayer _backgroundLayer;
CGPoint _center;

public MaterialActivityIndicatorRenderer()
{
VisualElement.VerifyVisualFlagEnabled();
Expand All @@ -32,6 +36,14 @@ protected override void OnElementChanged(ElementChangedEventArgs<ActivityIndicat
_defaultColorScheme = CreateColorScheme();

SetNativeControl(CreateNativeControl());

_backgroundLayer = new CAShapeLayer
{
LineWidth = 4,
FillColor = UIColor.Clear.CGColor,
Hidden = true
};
Control.Layer.InsertSublayer(_backgroundLayer, 0);
}

UpdateColor();
Expand All @@ -55,10 +67,24 @@ protected override MActivityIndicator CreateNativeControl()
{
return new MActivityIndicator
{
IndicatorMode = ActivityIndicatorMode.Indeterminate
IndicatorMode = ActivityIndicatorMode.Indeterminate,
StrokeWidth = 4,
Radius = 24
};
}

public override void LayoutSubviews()
{
base.LayoutSubviews();

if (_center != Control.Center)
{
_center = Control.Center;
_backgroundLayer.Path = UIBezierPath.FromArc(_center, Control.Radius - 2, 0, 360, true).CGPath;
}
SetBackgroundColor(Element.BackgroundColor);
}

protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
Expand All @@ -80,36 +106,16 @@ protected override void OnElementPropertyChanged(object sender, PropertyChangedE

protected override void SetBackgroundColor(Color color)
{
// Do not call base to avoid the actual background view changing color.
//base.SetBackgroundColor(color);

if (Control == null)
if (_backgroundLayer == null)
return;

// TODO: Investigate whether or not we want to look for the track
// layer and change the color. This will be brittle.
// For now, just show/hide the track.

if (color.IsDefault)
Control.TrackEnabled = false;
else
Control.TrackEnabled = true;

// handle the actual background color next to the main color
UpdateColor();
_backgroundLayer.Hidden = color.IsDefault;
_backgroundLayer.StrokeColor = color.ToCGColor();
}

void UpdateColor()
{
Color color = Element.Color;
Color backColor = Element.BackgroundColor;

if (!color.IsDefault)
_colorScheme.PrimaryColor = color.ToUIColor();
else if (!backColor.IsDefault)
_colorScheme.PrimaryColor = backColor.ToUIColor();
else
_colorScheme.PrimaryColor = _defaultColorScheme.PrimaryColor;
_colorScheme.PrimaryColor = Element.Color.IsDefault ? _defaultColorScheme.PrimaryColor : Element.Color.ToUIColor();
}

void UpdateIsRunning()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,18 @@
using System.ComponentModel;
using Android.Content;
using Android.Content.Res;
using Android.Graphics.Drawables;
using Android.Support.V4.View;
using Android.Views;
using Android.Widget;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android.FastRenderers;
using Xamarin.Forms.Platform.Android.Material;
using AColor = Android.Graphics.Color;
using AProgressBar = Android.Widget.ProgressBar;
using AView = Android.Views.View;

[assembly: ExportRenderer(typeof(Xamarin.Forms.ActivityIndicator), typeof(MaterialActivityIndicatorRenderer), new[] { typeof(VisualRendererMarker.Material) })]
[assembly: ExportRenderer(typeof(ActivityIndicator), typeof(MaterialActivityIndicatorRenderer), new[] { typeof(VisualRendererMarker.Material) })]

namespace Xamarin.Forms.Platform.Android.Material
{
Expand Down Expand Up @@ -111,8 +113,7 @@ protected virtual void OnElementChanged(ElementChangedEventArgs<ActivityIndicato

e.NewElement.PropertyChanged += OnElementPropertyChanged;

UpdatIsRunning();
UpdateColors();
UpdateColorsAndRuning();

ElevationHelper.SetElevation(this, e.NewElement);
}
Expand All @@ -122,10 +123,8 @@ protected virtual void OnElementPropertyChanged(object sender, PropertyChangedEv
{
ElementPropertyChanged?.Invoke(this, e);

if (e.PropertyName == ActivityIndicator.IsRunningProperty.PropertyName)
UpdatIsRunning();
else if (e.PropertyName == ActivityIndicator.ColorProperty.PropertyName || e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName)
UpdateColors();
if (e.IsOneOf(ActivityIndicator.IsRunningProperty, ActivityIndicator.ColorProperty, VisualElement.BackgroundColorProperty))
UpdateColorsAndRuning();
}

public override bool OnTouchEvent(MotionEvent e)
Expand All @@ -136,32 +135,32 @@ public override bool OnTouchEvent(MotionEvent e)
return _motionEventHelper.HandleMotionEvent(Parent, e);
}

void UpdateColors()
void UpdateColorsAndRuning()
{
if (Element == null || Control == null)
return;

// TODO: BackgroundColor is not supported by this control.
var background = Element.BackgroundColor.IsDefault
? AColor.Transparent
: Element.BackgroundColor.ToAndroid();
(_control.Background as GradientDrawable)?.SetColor(background);

Color progressColor = Element.Color;

if (progressColor.IsDefault)
if (Element.IsRunning)
{
var progress = MaterialColors.Light.PrimaryColor;
var progress = Element.Color.IsDefault
? MaterialColors.Light.PrimaryColor
: Element.Color.ToAndroid();
_control.IndeterminateTintList = ColorStateList.ValueOf(progress);
}
else
{
var progress = progressColor.ToAndroid();
_control.IndeterminateTintList = ColorStateList.ValueOf(progress);
_control.Visibility = Element.BackgroundColor.IsDefault
? ViewStates.Gone
: ViewStates.Visible;
_control.IndeterminateTintList = ColorStateList.ValueOf(AColor.Transparent);
}
}

void UpdatIsRunning()
{
_control.Visibility = Element.IsRunning ? ViewStates.Visible : ViewStates.Gone;
}

// IVisualElementRenderer

VisualElement IVisualElementRenderer.Element => Element;
Expand All @@ -179,7 +178,8 @@ SizeRequest IVisualElementRenderer.GetDesiredSize(int widthConstraint, int heigh
}

void IVisualElementRenderer.SetElement(VisualElement element) =>
Element = (element as ActivityIndicator) ?? throw new ArgumentException("Element must be of type ActivityIndicator.");
Element = (element as ActivityIndicator) ??
throw new ArgumentException($"{element?.GetType().FullName} is not compatible. {nameof(element)} must be of type {nameof(ActivityIndicator)}.");

void IVisualElementRenderer.SetLabelFor(int? id)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- innerRadius = (diameter / 2) - (thickness * 2) = 16dp -->
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="ring"
android:innerRadius="16dp"
android:thickness="4dp"
android:useLevel="false">
<solid android:color="#000" />
</shape>
1 change: 1 addition & 0 deletions Xamarin.Forms.Platform.Android/Resources/values/styles.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<style name="XamarinFormsMaterialProgressBarHorizontal" parent="Widget.AppCompat.ProgressBar.Horizontal">
</style>
<style name="XamarinFormsMaterialProgressBarCircular" parent="Widget.AppCompat.ProgressBar">
<item name="android:background">@drawable/MaterialActivityIndicatorBackground</item>
</style>
<style name="XamarinFormsMaterialButton" parent="Widget.MaterialComponents.Button">
<item name="android:insetTop">0dp</item>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,11 @@
</AndroidResource>
</ItemGroup>
<ItemGroup />
<ItemGroup>
<AndroidResource Include="Resources\drawable\MaterialActivityIndicatorBackground.xml">
<SubType>Designer</SubType>
</AndroidResource>
</ItemGroup>
<Target Name="BeforeBuild" Condition=" '$(CreateAllAndroidTargets)' == 'true' ">
<!-- create 8.1 binaries-->
<MSBuild Targets="Restore" Projects="@(ProjectToBuild)">
Expand Down

0 comments on commit b4d12ab

Please sign in to comment.