diff --git a/AiForms.Effects.Droid/AiForms.Effects.Droid.csproj b/AiForms.Effects.Droid/AiForms.Effects.Droid.csproj
index e381520..b12e500 100644
--- a/AiForms.Effects.Droid/AiForms.Effects.Droid.csproj
+++ b/AiForms.Effects.Droid/AiForms.Effects.Droid.csproj
@@ -27,6 +27,7 @@
4
None
+ 8.0
true
@@ -39,6 +40,7 @@
true
false
1591
+ 8.0
@@ -207,6 +209,7 @@
+
diff --git a/AiForms.Effects.Droid/GradientPlatformEffect.cs b/AiForms.Effects.Droid/GradientPlatformEffect.cs
new file mode 100644
index 0000000..9f20175
--- /dev/null
+++ b/AiForms.Effects.Droid/GradientPlatformEffect.cs
@@ -0,0 +1,105 @@
+using System;
+using System.ComponentModel;
+using System.Linq;
+using AiForms.Effects;
+using AiForms.Effects.Droid;
+using Android.Graphics.Drawables;
+using Xamarin.Forms;
+using Xamarin.Forms.Platform.Android;
+
+[assembly: ExportEffect(typeof(GradientPlatformEffect), nameof(Gradient))]
+namespace AiForms.Effects.Droid
+{
+ public class GradientPlatformEffect:AiEffectBase
+ {
+ Android.Views.View _view;
+ GradientDrawable _gradient;
+ Drawable _orgDrawable;
+
+ protected override void OnAttachedOverride()
+ {
+ _view = Container ?? Control;
+
+ _gradient = new GradientDrawable();
+ _orgDrawable = _view.Background;
+
+ UpdateGradient();
+ }
+
+ protected override void OnDetachedOverride()
+ {
+ if(!IsDisposed)
+ {
+ _view.Background = _orgDrawable;
+ _view.ClipToOutline = false;
+ System.Diagnostics.Debug.WriteLine($"{this.GetType().FullName} Detached Disposing");
+ }
+
+ _gradient?.Dispose();
+ _gradient = null;
+ _view = null;
+ System.Diagnostics.Debug.WriteLine($"{this.GetType().FullName} Detached completely");
+ }
+
+ protected override void OnElementPropertyChanged(PropertyChangedEventArgs args)
+ {
+ base.OnElementPropertyChanged(args);
+
+ if (!IsSupportedByApi)
+ return;
+
+ if (IsDisposed)
+ {
+ return;
+ }
+
+ if (args.PropertyName == Gradient.ColorsProperty.PropertyName ||
+ args.PropertyName == Gradient.OrientationProperty.PropertyName)
+ {
+ UpdateGradient();
+ }
+ }
+
+ void UpdateGradient()
+ {
+ var colors = Gradient.GetColors(Element);
+ if(colors == null)
+ {
+ return;
+ }
+
+ _gradient.SetColors(colors.Select(x => (int)x.ToAndroid()).ToArray());
+ _gradient.SetOrientation(ConvertOrientation());
+
+ _view.ClipToOutline = true; //not to overflow children
+ _view.SetBackground(_gradient);
+ }
+
+ GradientDrawable.Orientation ConvertOrientation()
+ {
+ var orientation = Gradient.GetOrientation(Element);
+
+ switch (orientation)
+ {
+ case GradientOrientation.LeftRight:
+ return GradientDrawable.Orientation.LeftRight;
+ case GradientOrientation.BlTr:
+ return GradientDrawable.Orientation.BlTr;
+ case GradientOrientation.BottomTop:
+ return GradientDrawable.Orientation.BottomTop;
+ case GradientOrientation.BrTl:
+ return GradientDrawable.Orientation.BrTl;
+ case GradientOrientation.RightLeft:
+ return GradientDrawable.Orientation.RightLeft;
+ case GradientOrientation.TrBl:
+ return GradientDrawable.Orientation.TrBl;
+ case GradientOrientation.TopBottom:
+ return GradientDrawable.Orientation.TopBottom;
+ case GradientOrientation.TlBr:
+ return GradientDrawable.Orientation.TlBr;
+ default:
+ return GradientDrawable.Orientation.LeftRight;
+ }
+ }
+ }
+}
diff --git a/AiForms.Effects.iOS/AiForms.Effects.iOS.csproj b/AiForms.Effects.iOS/AiForms.Effects.iOS.csproj
index c1e20d6..fbfa80c 100644
--- a/AiForms.Effects.iOS/AiForms.Effects.iOS.csproj
+++ b/AiForms.Effects.iOS/AiForms.Effects.iOS.csproj
@@ -28,6 +28,7 @@
+ 8.0
true
@@ -43,6 +44,7 @@
1591
+ 8.0
@@ -89,6 +91,7 @@
+
diff --git a/AiForms.Effects.iOS/GradientPlatformEffect.cs b/AiForms.Effects.iOS/GradientPlatformEffect.cs
new file mode 100644
index 0000000..006d2fe
--- /dev/null
+++ b/AiForms.Effects.iOS/GradientPlatformEffect.cs
@@ -0,0 +1,125 @@
+using System;
+using System.ComponentModel;
+using System.Linq;
+using AiForms.Effects;
+using AiForms.Effects.iOS;
+using CoreAnimation;
+using CoreGraphics;
+using UIKit;
+using Xamarin.Forms;
+using Xamarin.Forms.Platform.iOS;
+
+[assembly: ExportEffect(typeof(GradientPlatformEffect), nameof(Gradient))]
+namespace AiForms.Effects.iOS
+{
+ public class GradientPlatformEffect:PlatformEffect
+ {
+ UIView _view;
+ VisualElement _visualElement;
+ CAGradientLayer _layer;
+ bool _clipsToBounds;
+
+ protected override void OnAttached()
+ {
+ _view = Control ?? Container;
+ _visualElement = Element as VisualElement;
+ if(_visualElement == null)
+ {
+ Device.BeginInvokeOnMainThread(() => Gradient.SetOn(Element, false));
+ return;
+ }
+
+ if (Element is Label)
+ {
+ _view = Container;
+ }
+
+ _clipsToBounds = _view.ClipsToBounds;
+ _visualElement.SizeChanged += OnSizeChanged;
+ UpdateGradient();
+ }
+
+ protected override void OnDetached()
+ {
+ if(_visualElement != null)
+ {
+ _visualElement.SizeChanged -= OnSizeChanged;
+ }
+
+ if(_view != null)
+ {
+ _view.ClipsToBounds = _clipsToBounds;
+ }
+
+ _layer?.RemoveFromSuperLayer();
+ _layer?.Dispose();
+ _layer = null;
+
+ _view = null;
+ _visualElement = null;
+
+ System.Diagnostics.Debug.WriteLine($"Detached {GetType().Name} from {Element.GetType().FullName}");
+ }
+
+ protected override void OnElementPropertyChanged(PropertyChangedEventArgs args)
+ {
+ base.OnElementPropertyChanged(args);
+ if(args.PropertyName == Gradient.ColorsProperty.PropertyName ||
+ args.PropertyName == Gradient.OrientationProperty.PropertyName)
+ {
+ UpdateGradient();
+ }
+ }
+
+ private void OnSizeChanged(object sender, EventArgs e)
+ {
+ UpdateGradient();
+ }
+
+ void UpdateGradient()
+ {
+ var colors = Gradient.GetColors(Element);
+ if(colors == null)
+ {
+ return;
+ }
+
+ _layer?.RemoveFromSuperLayer();
+ _layer?.Dispose();
+
+ _layer = new CAGradientLayer();
+ _layer.Frame = new CGRect(0, 0, _visualElement.Width, _visualElement.Height);
+ _layer.Colors = colors.Select(x => x.ToCGColor()).ToArray();
+ (_layer.StartPoint,_layer.EndPoint) = ConvertPoint();
+ _view.Layer.InsertSublayer(_layer, 0);
+ _view.ClipsToBounds = true;
+ }
+
+ (CGPoint start,CGPoint end) ConvertPoint()
+ {
+ var orientation = Gradient.GetOrientation(Element);
+
+ switch(orientation)
+ {
+ case GradientOrientation.LeftRight:
+ return (new CGPoint(0, 0.5), new CGPoint(1, 0.5));
+ case GradientOrientation.BlTr:
+ return (new CGPoint(0, 1.0), new CGPoint(1, 0));
+ case GradientOrientation.BottomTop:
+ return (new CGPoint(0.5, 1), new CGPoint(0.5, 0));
+ case GradientOrientation.BrTl:
+ return (new CGPoint(1, 1), new CGPoint(0, 0));
+ case GradientOrientation.RightLeft:
+ return (new CGPoint(1, 0.5), new CGPoint(0, 0.5));
+ case GradientOrientation.TrBl:
+ return (new CGPoint(1, 0), new CGPoint(0, 1));
+ case GradientOrientation.TopBottom:
+ return (new CGPoint(0.5, 0), new CGPoint(0.5, 1));
+ case GradientOrientation.TlBr:
+ return (new CGPoint(0, 0), new CGPoint(1, 1));
+ default:
+ return (new CGPoint(0, 0.5), new CGPoint(1, 0.5));
+ }
+ }
+ }
+}
diff --git a/AiForms.Effects/AiForms.Effects.csproj b/AiForms.Effects/AiForms.Effects.csproj
index 3a452e6..d12e02a 100644
--- a/AiForms.Effects/AiForms.Effects.csproj
+++ b/AiForms.Effects/AiForms.Effects.csproj
@@ -2,13 +2,17 @@
netstandard2.0
- 1.1.2
+ 0.0.5-pre
true
bin\Release\netstandard2.0\AiForms.Effects.xml
1701;1702;1591
+ 8.0
+
+
+ 8.0
diff --git a/AiForms.Effects/Gradient.cs b/AiForms.Effects/Gradient.cs
new file mode 100644
index 0000000..d3e247c
--- /dev/null
+++ b/AiForms.Effects/Gradient.cs
@@ -0,0 +1,175 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Xamarin.Forms;
+using Xamarin.Forms.Xaml;
+
+namespace AiForms.Effects
+{
+ ///
+ /// GradientOrientation
+ ///
+ [TypeConverter(typeof(GradientOrientationTypeConverter))]
+ public enum GradientOrientation
+ {
+ ///
+ /// Left to Right
+ ///
+ LeftRight = 0,
+ ///
+ /// Bottom Left to Top Right
+ ///
+ BlTr = 45,
+ ///
+ /// Bottom to Top
+ ///
+ BottomTop = 90,
+ ///
+ /// Bottom Right to Top Left
+ ///
+ BrTl = 135,
+ ///
+ /// Right to Left
+ ///
+ RightLeft = 180,
+ ///
+ /// Top Right to Bottom Left
+ ///
+ TrBl = 225,
+ ///
+ /// Top to Bottom
+ ///
+ TopBottom = 270,
+ ///
+ /// Top Left to Bottom Right
+ ///
+ TlBr = 315,
+ }
+
+ ///
+ /// GradientOrientationTypeConverter
+ ///
+ [TypeConversion(typeof(GradientOrientation))]
+ public class GradientOrientationTypeConverter:TypeConverter
+ {
+ public override object ConvertFromInvariantString(string value)
+ {
+ if (value != null)
+ {
+ if (Enum.TryParse(value, true, out GradientOrientation orientation))
+ return orientation;
+ }
+ throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(GradientOrientation)}");
+ }
+ }
+
+ ///
+ /// GradientColors
+ ///
+ [TypeConverter(typeof(ColorsTypeConverter))]
+ public class GradientColors:List
+ {
+ public GradientColors() : base() { }
+ public GradientColors(IEnumerable colors) : base(colors) { }
+ }
+
+ ///
+ /// ColorsTypeConverter
+ ///
+ [TypeConversion(typeof(GradientColors))]
+ public class ColorsTypeConverter : TypeConverter
+ {
+ public override object ConvertFromInvariantString(string value)
+ {
+ if (value != null)
+ {
+ var colors = value.Split(',');
+ var conv = new ColorTypeConverter();
+
+ return new GradientColors(colors.Select(x => (Color)conv.ConvertFromInvariantString(x)));
+ }
+
+ throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(GradientColors)}");
+ }
+ }
+
+ ///
+ /// Gradient
+ ///
+ public static class Gradient
+ {
+ ///
+ /// The on property.
+ ///
+ public static readonly BindableProperty OnProperty =
+ BindableProperty.CreateAttached(
+ propertyName: "On",
+ returnType: typeof(bool?),
+ declaringType: typeof(Gradient),
+ defaultValue: null,
+ propertyChanged: AiRoutingEffectBase.ToggleEffectHandler
+ );
+
+ ///
+ /// Sets the on.
+ ///
+ /// View.
+ /// Value.
+ public static void SetOn(BindableObject view, bool? value)
+ {
+ view.SetValue(OnProperty, value);
+ }
+
+ ///
+ /// Gets the on.
+ ///
+ /// The on.
+ /// View.
+ public static bool? GetOn(BindableObject view)
+ {
+ return (bool?)view.GetValue(OnProperty);
+ }
+
+ public static readonly BindableProperty ColorsProperty =
+ BindableProperty.CreateAttached(
+ "Colors",
+ typeof(GradientColors),
+ typeof(Gradient),
+ default(GradientColors),
+ propertyChanged: AiRoutingEffectBase.AddEffectHandler
+ );
+
+ public static void SetColors(BindableObject view, GradientColors value)
+ {
+ view.SetValue(ColorsProperty, value);
+ }
+
+ public static GradientColors GetColors(BindableObject view)
+ {
+ return (GradientColors)view.GetValue(ColorsProperty);
+ }
+
+ public static readonly BindableProperty OrientationProperty =
+ BindableProperty.CreateAttached(
+ "Orientation",
+ typeof(GradientOrientation),
+ typeof(Gradient),
+ default(GradientOrientation)
+ );
+
+ public static void SetOrientation(BindableObject view, GradientOrientation value)
+ {
+ view.SetValue(OrientationProperty, value);
+ }
+
+ public static GradientOrientation GetOrientation(BindableObject view)
+ {
+ return (GradientOrientation)view.GetValue(OrientationProperty);
+ }
+ }
+
+ internal class GradientRoutingEffect : AiRoutingEffectBase
+ {
+ public GradientRoutingEffect() : base("AiForms." + nameof(Gradient)) { }
+ }
+}
diff --git a/README-ja.md b/README-ja.md
index 415a789..71d1c7d 100644
--- a/README-ja.md
+++ b/README-ja.md
@@ -5,10 +5,12 @@ AiForms.Effect は Android と iOS に特化することにより、標準のコ
![Build status](https://kamusoft.visualstudio.com/NugetCI/_apis/build/status/AiForms.Effects)
## 機能
+* [Gradient](#gradient)
+ * グラデーション背景を設定する。
* [Floating](#floating)
- * ページの前面の任意の場所に複数のフローティングな要素(FABなど)を配置します。
+ * ページの前面の任意の場所に複数のフローティングな要素(FABなど)を配置する。
* [Feedback](#feedback)
- * タッチフィードバック効果(色やシステム音)を追加。コマンドは含みません。
+ * タッチフィードバック効果(色やシステム音)を追加。コマンドは含まない。
* [AddTouch](#addtouch)
* 各種タッチイベントを追加
* [SizeToFit](#sizetofit)
@@ -106,6 +108,33 @@ protected override void OnCreate(Bundle bundle) {
}
```
+## Gradient
+
+任意のレイアウト要素にグラデーション効果をつけるEffectです。
+レイアウト以外のコントロールにも使用できますが、完全ではありません。
+
+### Properties
+
+* On
+ * Effect On/Off (true is On)
+* Colors (trigger)
+ * グラデーションに使う色を設定します。
+ * Xamlではカンマ区切りで複数設定でき、順番にグラデーションに適用されます。
+ * c# では GradientColorsクラスのインスタンスを指定します。
+* Orientation
+ * グラデーションの方向を指定します。
+ * 8方向の指定が可能です。
+
+### 使い方
+
+```xml
+
+
+
+```
+
## Floating
ページの上の任意の場所に複数のフローティングView (Floating Action Buttonなど) を配置するEffectです。
diff --git a/README.md b/README.md
index 0edcc7e..16b000a 100644
--- a/README.md
+++ b/README.md
@@ -7,6 +7,8 @@ AiForms.Effects is the effects library that provides you with more flexible func
![Build status](https://kamusoft.visualstudio.com/NugetCI/_apis/build/status/AiForms.Effects)
## Features
+* [Gradient](#gradient)
+ * set a gradient background.
* [Floating](#floating)
* arrange some floating views (e.g. FAB) at any place over a page.
* [Feedback](#feedback)
@@ -113,6 +115,33 @@ protected override void OnCreate(Bundle bundle) {
}
```
+## Gradient
+
+This is the effect that the gradient background is set to a Layout Element.
+Although It can be set to the controls except with Layouts, its implementation is not complete.
+
+### Properties
+
+* On
+ * Effect On/Off (true is On)
+* Colors (trigger)
+ * The colors of gradient.
+ * Can set multiple colors with comma-separated in Xaml.
+ * Specify the instance of the GradientColors class in c#.
+* Orientation
+ * Specify the direction for the gradient.
+ * Can select from 8 directions.
+
+### How to write with XAML
+
+```xml
+
+
+
+```
+
## Floating
This is the effect that arranges some floating views (e.g. FAB) at any place on a page.
diff --git a/Tests/AiEffects.TestApp/AiEffects.TestApp/ViewModels/GradientPageViewModel.cs b/Tests/AiEffects.TestApp/AiEffects.TestApp/ViewModels/GradientPageViewModel.cs
new file mode 100644
index 0000000..312ce95
--- /dev/null
+++ b/Tests/AiEffects.TestApp/AiEffects.TestApp/ViewModels/GradientPageViewModel.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+using AiForms.Effects;
+using Prism.Mvvm;
+using Reactive.Bindings;
+using Xamarin.Forms;
+
+namespace AiEffects.TestApp.ViewModels
+{
+ public class GradientPageViewModel:BindableBase
+ {
+ public ReactiveProperty EffectOn { get; } = new ReactiveProperty(false);
+ public ReactivePropertySlim Colors { get; } = new ReactivePropertySlim();
+ public ReactivePropertySlim Orientation { get; } = new ReactivePropertySlim();
+
+ public ReactiveCommand ChangeColorsCommand { get; } = new ReactiveCommand();
+ public ReactiveCommand ChangeOrientationCommand { get; } = new ReactiveCommand();
+
+ GradientColors _colors1 = new GradientColors(new List
+ {
+ Color.Blue,Color.LightGray
+ });
+ GradientColors _colors2 = new GradientColors(new List
+ {
+ Color.Red, Color.Green,Color.LightGray
+ });
+
+ public GradientPageViewModel()
+ {
+ Colors.Value = _colors1;
+ Orientation.Value = GradientOrientation.LeftRight;
+
+ ChangeColorsCommand.Subscribe(x =>
+ {
+ var p = int.Parse(x);
+ Colors.Value = p == 2 ? _colors1 : _colors2;
+ });
+
+ ChangeOrientationCommand.Subscribe(x =>
+ {
+ var p = int.Parse(x);
+ Orientation.Value = (GradientOrientation)p;
+ });
+ }
+ }
+}
diff --git a/Tests/AiEffects.TestApp/AiEffects.TestApp/Views/GradientPage.xaml b/Tests/AiEffects.TestApp/AiEffects.TestApp/Views/GradientPage.xaml
new file mode 100644
index 0000000..76bb85c
--- /dev/null
+++ b/Tests/AiEffects.TestApp/AiEffects.TestApp/Views/GradientPage.xaml
@@ -0,0 +1,240 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Tests/AiEffects.TestApp/AiEffects.TestApp/Views/GradientPage.xaml.cs b/Tests/AiEffects.TestApp/AiEffects.TestApp/Views/GradientPage.xaml.cs
new file mode 100644
index 0000000..1718922
--- /dev/null
+++ b/Tests/AiEffects.TestApp/AiEffects.TestApp/Views/GradientPage.xaml.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+
+using Xamarin.Forms;
+
+namespace AiEffects.TestApp.Views
+{
+ public partial class GradientPage : ContentPage
+ {
+ public GradientPage()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/Tests/AiEffects.TestApp/AiEffects.TestApp/Views/MainPage.xaml b/Tests/AiEffects.TestApp/AiEffects.TestApp/Views/MainPage.xaml
index fb63f76..d69b197 100644
--- a/Tests/AiEffects.TestApp/AiEffects.TestApp/Views/MainPage.xaml
+++ b/Tests/AiEffects.TestApp/AiEffects.TestApp/Views/MainPage.xaml
@@ -15,7 +15,10 @@
-
+
+
+
diff --git a/nuget/AzurePipelines.nuspec b/nuget/AzurePipelines.nuspec
index 19e8d3c..87486c2 100644
--- a/nuget/AzurePipelines.nuspec
+++ b/nuget/AzurePipelines.nuspec
@@ -13,16 +13,9 @@
Xamarin.Forms Effects(add Border / add placeholder / add Text / add Command / add NumberPicker, TimePicker and DatePicker / alter color for switch and slider / alter LineHeight of Label and Editor / Button to flat / Size to fit for Label / add touch events / Floating / Feedback) for iOS / Android
-## Changes
+## New fueature
-* Feedback – On Android, a button is now ringed a sound. #50
-
-## Bug fixes
-
-* AddCommand – Fixed AddCommand.SyncCanExecute does not work on Android #53
-* Android – Fixed null exception when popping a page. #54
-* AddText – Fixed the end of characters is sometimes omitted #48.
-* Feedback – Fixed Android OnOverlayTouch crash #49.
+* Gradient – the effect that the gradient background is set to a Layout Element.
Xamarin.Forms Effects Command NumberPikcer LineHeight LineSpacing FlatButton Validation SoundEffect Border TimePicker DatePicker Placeholder Color SizeToFit TouchEvents Floating