[Material] [Android, iOS] Added Slider and ProgressBar (#5209)

* [Android Material] Linear Progress Indicator (#5079)

Merging into the material "slider" / "progress" bar branch so that we can share some code as they are the same control

* [Material] [Slider, ProgressBar] Updated the progress bard and added the slider

* Renamed the gallery

fixes #5008
fixes #5079
fixes #5018
This commit is contained in:
Matthew Leibowitz 2019-02-14 01:36:55 +02:00 коммит произвёл Samantha Houts
Родитель c1ae194404
Коммит 9ab1fff85f
13 изменённых файлов: 675 добавлений и 74 удалений

Просмотреть файл

@ -0,0 +1,171 @@
using System;
namespace Xamarin.Forms.Controls
{
public class ColorPicker : ContentView
{
public static readonly BindableProperty UseDefaultProperty = BindableProperty.Create(nameof(UseDefault), typeof(bool), typeof(ColorPicker), false,
propertyChanged: OnColorChanged);
public static readonly BindableProperty ColorProperty = BindableProperty.Create(nameof(Color), typeof(Color), typeof(ColorPicker), Color.Default,
propertyChanged: OnColorChanged);
public static readonly BindableProperty TitleProperty = BindableProperty.Create(nameof(Title), typeof(string), typeof(ColorPicker), "Pick a color:",
propertyChanged: OnTitleChanged);
static readonly string[] _components = { "R", "G", "B", "A" };
Label _titleLabel;
Slider[] _sliders;
BoxView _box;
Label _hexLabel;
Switch _useDefault;
public ColorPicker()
{
var grid = new Grid
{
Padding = 0,
RowSpacing = 3,
ColumnSpacing = 3,
ColumnDefinitions =
{
new ColumnDefinition { Width = 20 },
new ColumnDefinition { Width = GridLength.Star },
new ColumnDefinition { Width = 60 },
},
};
_titleLabel = new Label { Text = (string)TitleProperty.DefaultValue };
grid.AddChild(_titleLabel, 0, 0, 2);
_useDefault = new Switch
{
IsToggled = true,
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center
};
_useDefault.Toggled += OnUseDefaultToggled;
grid.AddChild(_useDefault, 2, 0);
_sliders = new Slider[_components.Length];
for (var i = 0; i < _components.Length; i++)
{
_sliders[i] = new Slider
{
VerticalOptions = LayoutOptions.Center,
Minimum = 0,
Maximum = 255,
Value = 255
};
_sliders[i].ValueChanged += OnColorSliderChanged;
var label = new Label
{
Text = _components[i],
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center
};
grid.AddChild(label, 0, i + 1);
grid.AddChild(_sliders[i], 1, i + 1);
}
_box = new BoxView
{
Color = Color,
HorizontalOptions = LayoutOptions.Fill,
VerticalOptions = LayoutOptions.Fill,
};
grid.AddChild(_box, 2, 1, 1, 3);
_hexLabel = new Label
{
Text = ColorToHex(Color),
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center,
FontSize = 10,
};
grid.AddChild(_hexLabel, 2, 4);
Content = grid;
}
public string Title
{
get => (string)GetValue(TitleProperty);
set => SetValue(TitleProperty, value);
}
public bool UseDefault
{
get => (bool)GetValue(UseDefaultProperty);
set => SetValue(UseDefaultProperty, value);
}
public Color Color
{
get => (Color)GetValue(ColorProperty);
set => SetValue(ColorProperty, value);
}
public event EventHandler<ColorPickedEventArgs> ColorPicked;
void OnColorSliderChanged(object sender, ValueChangedEventArgs e)
{
var color = Color.FromRgba(
(int)_sliders[0].Value,
(int)_sliders[1].Value,
(int)_sliders[2].Value,
(int)_sliders[3].Value);
Color = color;
}
private void OnUseDefaultToggled(object sender, ToggledEventArgs e)
{
UseDefault = !e.Value;
foreach (var slider in _sliders)
slider.IsEnabled = e.Value;
}
static void OnColorChanged(BindableObject bindable, object oldValue, object newValue)
{
if (bindable is ColorPicker picker)
{
var color = picker.UseDefault ? Color.Default : picker.Color;
picker._hexLabel.Text = color.IsDefault ? "<default>" : ColorToHex(color);
picker._box.Color = color;
picker.ColorPicked?.Invoke(picker, new ColorPickedEventArgs(color));
}
}
static void OnTitleChanged(BindableObject bindable, object oldValue, object newValue)
{
if (bindable is ColorPicker picker)
{
picker._titleLabel.Text = picker.Title;
}
}
static string ColorToHex(Color color)
{
var a = (int)(color.A * 255);
var r = (int)(color.R * 255);
var g = (int)(color.G * 255);
var b = (int)(color.B * 255);
var value = a << 24 | r << 16 | g << 8 | b;
return "#" + value.ToString("X");
}
}
public class ColorPickedEventArgs : EventArgs
{
public ColorPickedEventArgs(Color color)
{
Color = color;
}
public Color Color { get; }
}
}

Просмотреть файл

@ -321,6 +321,7 @@ namespace Xamarin.Forms.Controls
new GalleryPageFactory(() => new OpenGLViewCoreGalleryPage(), "OpenGLView Gallery"),
new GalleryPageFactory(() => new PickerCoreGalleryPage(), "Picker Gallery"),
new GalleryPageFactory(() => new ProgressBarCoreGalleryPage(), "ProgressBar Gallery"),
new GalleryPageFactory(() => new MaterialProgressBarGallery(), "[Material] ProgressBar & Slider Gallery"),
new GalleryPageFactory(() => new ScrollGallery(), "ScrollView Gallery"),
new GalleryPageFactory(() => new ScrollGallery(ScrollOrientation.Horizontal), "ScrollView Gallery Horizontal"),
new GalleryPageFactory(() => new ScrollGallery(ScrollOrientation.Both), "ScrollView Gallery 2D"),

Просмотреть файл

@ -0,0 +1,118 @@
using System;
namespace Xamarin.Forms.Controls
{
public class MaterialProgressBarGallery : ContentPage
{
public MaterialProgressBarGallery()
{
Visual = VisualMarker.Material;
var progressBar = new ProgressBar { Progress = 0.5 };
var slider = new Slider { Value = 0.5 };
var primaryPicker = new ColorPicker { Title = "Primary Color" };
primaryPicker.ColorPicked += (_, e) =>
{
progressBar.ProgressColor = e.Color;
slider.MinimumTrackColor = e.Color;
};
var backgroundPicker = new ColorPicker { Title = "Background Color" };
backgroundPicker.ColorPicked += (_, e) =>
{
progressBar.BackgroundColor = e.Color;
slider.MaximumTrackColor = e.Color;
};
var thumbPicker = new ColorPicker { Title = "Thumb Color" };
thumbPicker.ColorPicked += (_, e) =>
{
slider.ThumbColor = e.Color;
};
var valuePicker = CreateValuePicker("Value / Progress", value =>
{
progressBar.Progress = value / 100.0;
slider.Value = value / 100.0;
});
var heightPicker = CreateValuePicker("Height", value =>
{
progressBar.HeightRequest = value;
slider.HeightRequest = value;
});
Content = new StackLayout
{
Padding = 10,
Spacing = 10,
Children =
{
new ScrollView
{
Margin = new Thickness(-10, 0),
Content = new StackLayout
{
Padding = 10,
Spacing = 10,
Children =
{
primaryPicker,
backgroundPicker,
thumbPicker,
valuePicker,
heightPicker,
}
}
},
new BoxView
{
HeightRequest = 1,
Margin = new Thickness(-10, 0),
Color = Color.Black
},
progressBar,
slider
}
};
}
Grid CreateValuePicker(string title, Action<double> changed)
{
// 50%
Slider slider = new Slider(0, 100, 50);
var actions = new Grid
{
Padding = 0,
ColumnSpacing = 6,
RowSpacing = 6,
ColumnDefinitions =
{
new ColumnDefinition { Width = 10 },
new ColumnDefinition { Width = GridLength.Star },
new ColumnDefinition { Width = 30 }
}
};
actions.AddChild(new Label { Text = title }, 0, 0, 3);
var valueLabel = new Label
{
Text = slider.Value.ToString(),
HorizontalOptions = LayoutOptions.End
};
slider.ValueChanged += (_, e) =>
{
changed?.Invoke(slider.Value);
valueLabel.Text = e.NewValue.ToString("0");
};
actions.AddChild(new Label { Text = "V" }, 0, 1);
actions.AddChild(slider, 1, 1);
actions.AddChild(valueLabel, 2, 1);
return actions;
}
}
}

Просмотреть файл

@ -38,9 +38,7 @@ namespace Xamarin.Forms
}, propertyChanged: (bindable, oldValue, newValue) =>
{
var slider = (Slider)bindable;
EventHandler<ValueChangedEventArgs> eh = slider.ValueChanged;
if (eh != null)
eh(slider, new ValueChangedEventArgs((double)oldValue, (double)newValue));
slider.ValueChanged?.Invoke(slider, new ValueChangedEventArgs((double)oldValue, (double)newValue));
});
public static readonly BindableProperty MinimumTrackColorProperty = BindableProperty.Create(nameof(MinimumTrackColor), typeof(Color), typeof(Slider), Color.Default);

Просмотреть файл

@ -10,8 +10,6 @@ namespace Xamarin.Forms.Platform.iOS.Material
{
public class MaterialProgressBarRenderer : ViewRenderer<ProgressBar, MProgressView>
{
const float BackgroundAlpha = 0.3f;
BasicColorScheme _defaultColorScheme;
BasicColorScheme _colorScheme;
@ -51,7 +49,7 @@ namespace Xamarin.Forms.Platform.iOS.Material
var cs = MaterialColors.Light.CreateColorScheme();
return new BasicColorScheme(
cs.PrimaryColor,
cs.PrimaryColor.ColorWithAlpha(BackgroundAlpha),
cs.PrimaryColor.ColorWithAlpha(MaterialColors.SliderTrackAlpha),
cs.PrimaryColor);
}
@ -123,9 +121,6 @@ namespace Xamarin.Forms.Platform.iOS.Material
void UpdateAllColors()
{
// TODO: Fix this once Google implements the new way.
// Right now, copy what is done with the activity indicator.
Color progressColor = Element.ProgressColor;
Color backgroundColor = Element.BackgroundColor;
@ -144,8 +139,6 @@ namespace Xamarin.Forms.Platform.iOS.Material
// handle the case where only the background is set
var background = backgroundColor.ToUIColor();
// TODO: Potentially override background alpha to match material design.
// TODO: Potentially override primary color to match material design.
_colorScheme = new BasicColorScheme(
_defaultColorScheme.PrimaryColor,
background,
@ -160,9 +153,10 @@ namespace Xamarin.Forms.Platform.iOS.Material
// handle the case where only the progress is set
var progress = progressColor.ToUIColor();
progress.GetRGBA(out _, out _, out _, out var alpha);
_colorScheme = new BasicColorScheme(
progress,
progress.ColorWithAlpha(BackgroundAlpha),
progress.ColorWithAlpha(alpha * MaterialColors.SliderTrackAlpha),
progress);
}
else
@ -171,7 +165,6 @@ namespace Xamarin.Forms.Platform.iOS.Material
var background = backgroundColor.ToUIColor();
var progress = progressColor.ToUIColor();
// TODO: Potentially override alpha to match material design.
_colorScheme = new BasicColorScheme(
progress,
background,

Просмотреть файл

@ -141,15 +141,19 @@ namespace Xamarin.Forms.Platform.iOS.Material
if (minColor.IsDefault && maxColor.IsDefault && thumbColor.IsDefault)
return;
// TODO: Potentially override alpha to match material design.
if (!minColor.IsDefault)
{
Control.SetTrackFillColor(minColor.ToUIColor(), UIControlState.Normal);
// if no max color was specified, then use a shade of the min
if (maxColor.IsDefault)
Control.SetTrackBackgroundColor(MatchAlpha(minColor, Control.GetTrackBackgroundColor(UIControlState.Normal)), UIControlState.Normal);
{
Control.GetTrackBackgroundColor(UIControlState.Normal).GetRGBA(out _, out _, out _, out var baseAlpha);
Control.SetTrackBackgroundColor(minColor.MultiplyAlpha(baseAlpha).ToUIColor(), UIControlState.Normal);
}
if (thumbColor.IsDefault)
Control.SetThumbColor(minColor.ToUIColor(), UIControlState.Normal);
}
if (!maxColor.IsDefault)
@ -157,12 +161,6 @@ namespace Xamarin.Forms.Platform.iOS.Material
if (!thumbColor.IsDefault)
Control.SetThumbColor(thumbColor.ToUIColor(), UIControlState.Normal);
UIColor MatchAlpha(Color color, UIColor alphaColor)
{
alphaColor.GetRGBA(out _, out _, out _, out var a);
return color.ToUIColor().ColorWithAlpha(a);
}
}
void OnControlValueChanged(object sender, EventArgs eventArgs)

Просмотреть файл

@ -3,7 +3,10 @@
#if __ANDROID__
using Android.Content.Res;
using Android.Graphics;
using AColor = Android.Graphics.Color;
using AProgressBar = Android.Widget.ProgressBar;
using ASeekBar = Android.Widget.AbsSeekBar;
#else
using MaterialComponents;
using AColor = UIKit.UIColor;
@ -19,6 +22,15 @@ namespace Xamarin.Forms.Platform.iOS.Material
// https://github.com/material-components/material-components-android/blob/3637c23078afc909e42833fd1c5fd47bb3271b5f/lib/java/com/google/android/material/color/res/values/colors.xml
internal static class MaterialColors
{
// https://github.com/material-components/material-components-ios/blob/v76.0.0/components/Slider/src/ColorThemer/MDCSliderColorThemer.m#L21
const float kSliderBaselineDisabledFillAlpha = 0.32f;
const float kSliderBaselineEnabledBackgroundAlpha = 0.24f;
const float kSliderBaselineDisabledBackgroundAlpha = 0.12f;
const float kSliderBaselineEnabledTicksAlpha = 0.54f;
const float kSliderBaselineDisabledTicksAlpha = 0.12f;
public const float SliderTrackAlpha = kSliderBaselineEnabledBackgroundAlpha;
// values based on
// copying to match iOS
// TODO generalize into xplat classes
@ -96,7 +108,7 @@ namespace Xamarin.Forms.Platform.iOS.Material
};
public static readonly int[][] EntryUnderlineStates =
{
{
new []{ global::Android.Resource.Attribute.StateFocused },
new []{ -global::Android.Resource.Attribute.StateFocused },
};
@ -137,6 +149,71 @@ namespace Xamarin.Forms.Platform.iOS.Material
internal static AColor WithAlpha(this AColor color, double alpha) =>
new AColor(color.R, color.G, color.B, (byte)(alpha * 255));
internal static void ApplySeekBarColors(this ASeekBar seekBar, Color progressColor, Color backgroundColor, Color thumbColor)
{
seekBar.ApplyProgressBarColors(progressColor, backgroundColor);
if (thumbColor.IsDefault)
{
// reset everything to defaults
seekBar.ThumbTintList = seekBar.ProgressTintList;
}
else
{
// handle the case where the thumb is set
var thumb = thumbColor.ToAndroid();
seekBar.ThumbTintList = ColorStateList.ValueOf(thumb);
}
}
internal static void ApplyProgressBarColors(this AProgressBar progressBar, Color progressColor, Color backgroundColor)
{
AColor defaultProgress = Dark.PrimaryColor;
if (progressColor.IsDefault)
{
if (backgroundColor.IsDefault)
{
// reset everything to defaults
progressBar.ProgressTintList = ColorStateList.ValueOf(defaultProgress);
progressBar.ProgressBackgroundTintList = ColorStateList.ValueOf(defaultProgress);
progressBar.ProgressBackgroundTintMode = PorterDuff.Mode.SrcIn;
}
else
{
// handle the case where only the background is set
var background = backgroundColor.ToAndroid();
progressBar.ProgressTintList = ColorStateList.ValueOf(defaultProgress);
progressBar.ProgressBackgroundTintList = ColorStateList.ValueOf(background);
progressBar.ProgressBackgroundTintMode = PorterDuff.Mode.SrcOver;
}
}
else
{
if (backgroundColor.IsDefault)
{
// handle the case where only the progress is set
var progress = progressColor.ToAndroid();
progressBar.ProgressTintList = ColorStateList.ValueOf(progress);
progressBar.ProgressBackgroundTintList = ColorStateList.ValueOf(progress);
progressBar.ProgressBackgroundTintMode = PorterDuff.Mode.SrcIn;
}
else
{
// handle the case where both are set
var background = backgroundColor.ToAndroid();
var progress = progressColor.ToAndroid();
progressBar.ProgressTintList = ColorStateList.ValueOf(progress);
progressBar.ProgressBackgroundTintList = ColorStateList.ValueOf(background);
progressBar.ProgressBackgroundTintMode = PorterDuff.Mode.SrcOver;
}
}
}
#endif
@ -232,6 +309,15 @@ namespace Xamarin.Forms.Platform.iOS.Material
static AColor WithMultipliedAlpha(AColor color, float alpha)
{
#if __ANDROID__
return color.WithAlpha(color.A / 255f * alpha);
#else
return color.ColorWithAlpha(color.CGColor.Alpha / 255f * alpha);
#endif
}
static AColor WithAlpha(AColor color, float alpha)
{
#if __ANDROID__

Просмотреть файл

@ -2,18 +2,15 @@
using System;
using System.ComponentModel;
using Android.Content;
using Android.Content.Res;
using Android.Graphics;
using Android.Support.V4.View;
using Android.Views;
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.ProgressBar), typeof(MaterialProgressBarRenderer), new[] { typeof(VisualRendererMarker.Material) })]
[assembly: ExportRenderer(typeof(ProgressBar), typeof(MaterialProgressBarRenderer), new[] { typeof(VisualRendererMarker.Material) })]
namespace Xamarin.Forms.Platform.Android.Material
{
@ -122,7 +119,6 @@ namespace Xamarin.Forms.Platform.Android.Material
protected virtual void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
ElementPropertyChanged?.Invoke(this, e);
if (e.PropertyName == ProgressBar.ProgressProperty.PropertyName)
UpdateProgress();
else if (e.PropertyName == ProgressBar.ProgressColorProperty.PropertyName || e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName)
@ -142,51 +138,7 @@ namespace Xamarin.Forms.Platform.Android.Material
if (Element == null || Control == null)
return;
Color progressColor = Element.ProgressColor;
Color backgroundColor = Element.BackgroundColor;
var defaultProgress = MaterialColors.Light.PrimaryColor;
if (progressColor.IsDefault && backgroundColor.IsDefault)
{
// reset everything to defaults
ProgressTintList = ColorStateList.ValueOf(defaultProgress);
ProgressBackgroundTintList = ColorStateList.ValueOf(defaultProgress);
ProgressBackgroundTintMode = PorterDuff.Mode.SrcIn;
}
else if (progressColor.IsDefault && !backgroundColor.IsDefault)
{
// handle the case where only the background is set
var background = backgroundColor.ToAndroid();
// TODO: Potentially override primary color to match material design.
ProgressTintList = ColorStateList.ValueOf(defaultProgress);
ProgressBackgroundTintList = ColorStateList.ValueOf(background);
// TODO: Potentially override background alpha to match material design.
ProgressBackgroundTintMode = PorterDuff.Mode.SrcOver;
}
else if (!progressColor.IsDefault && backgroundColor.IsDefault)
{
// handle the case where only the progress is set
var progress = progressColor.ToAndroid();
ProgressTintList = ColorStateList.ValueOf(progress);
ProgressBackgroundTintList = ColorStateList.ValueOf(progress);
ProgressBackgroundTintMode = PorterDuff.Mode.SrcIn;
}
else
{
// handle the case where both are set
var background = backgroundColor.ToAndroid();
var progress = progressColor.ToAndroid();
ProgressTintList = ColorStateList.ValueOf(progress);
ProgressBackgroundTintList = ColorStateList.ValueOf(background);
// TODO: Potentially override alpha to match material design.
ProgressBackgroundTintMode = PorterDuff.Mode.SrcOver;
}
this.ApplyProgressBarColors(Element.ProgressColor, Element.BackgroundColor);
}
void UpdateProgress()
@ -207,7 +159,7 @@ namespace Xamarin.Forms.Platform.Android.Material
SizeRequest IVisualElementRenderer.GetDesiredSize(int widthConstraint, int heightConstraint)
{
Measure(widthConstraint, heightConstraint);
return new SizeRequest(new Size(Control.MeasuredWidth, Control.MeasuredHeight), new Size());
return new SizeRequest(new Size(Control.MeasuredWidth, Context.ToPixels(4)), new Size(Context.ToPixels(4), Context.ToPixels(4)));
}
void IVisualElementRenderer.SetElement(VisualElement element) =>

Просмотреть файл

@ -0,0 +1,226 @@
#if __ANDROID_28__
using System;
using System.ComponentModel;
using Android.Content;
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 AView = Android.Views.View;
[assembly: ExportRenderer(typeof(Xamarin.Forms.Slider), typeof(MaterialSliderRenderer), new[] { typeof(VisualRendererMarker.Material) })]
namespace Xamarin.Forms.Platform.Android.Material
{
public class MaterialSliderRenderer : SeekBar,
SeekBar.IOnSeekBarChangeListener,
IVisualElementRenderer, IViewRenderer, ITabStop
{
const double MaximumValue = 10000.0;
int? _defaultLabelFor;
bool _disposed;
Slider _element;
VisualElementTracker _visualElementTracker;
VisualElementRenderer _visualElementRenderer;
MotionEventHelper _motionEventHelper;
double _max = 0.0;
double _min = 0.0;
public event EventHandler<VisualElementChangedEventArgs> ElementChanged;
public event EventHandler<PropertyChangedEventArgs> ElementPropertyChanged;
public MaterialSliderRenderer(Context context)
: base(new ContextThemeWrapper(context, Resource.Style.XamarinFormsMaterialSlider), null, Resource.Style.XamarinFormsMaterialSlider)
{
VisualElement.VerifyVisualFlagEnabled();
SetOnSeekBarChangeListener(this);
Max = (int)MaximumValue;
_visualElementRenderer = new VisualElementRenderer(this);
_motionEventHelper = new MotionEventHelper();
}
protected SeekBar Control => this;
protected Slider Element
{
get { return _element; }
set
{
if (_element == value)
return;
var oldElement = _element;
_element = value;
OnElementChanged(new ElementChangedEventArgs<Slider>(oldElement, _element));
_element?.SendViewInitialized(this);
_motionEventHelper.UpdateElement(_element);
}
}
double Value
{
get { return _min + (_max - _min) * (Control.Progress / MaximumValue); }
set { Control.Progress = (int)((value - _min) / (_max - _min) * MaximumValue); }
}
protected override void Dispose(bool disposing)
{
if (_disposed)
return;
_disposed = true;
if (disposing)
{
_visualElementTracker?.Dispose();
_visualElementTracker = null;
_visualElementRenderer?.Dispose();
_visualElementRenderer = null;
if (Element != null)
{
Element.PropertyChanged -= OnElementPropertyChanged;
if (Platform.GetRenderer(Element) == this)
Element.ClearValue(Platform.RendererProperty);
}
}
base.Dispose(disposing);
}
protected virtual void OnElementChanged(ElementChangedEventArgs<Slider> e)
{
ElementChanged?.Invoke(this, new VisualElementChangedEventArgs(e.OldElement, e.NewElement));
if (e.OldElement != null)
{
e.OldElement.PropertyChanged -= OnElementPropertyChanged;
}
if (e.NewElement != null)
{
this.EnsureId();
if (_visualElementTracker == null)
_visualElementTracker = new VisualElementTracker(this);
e.NewElement.PropertyChanged += OnElementPropertyChanged;
UpdateValue();
UpdateColors();
ElevationHelper.SetElevation(this, e.NewElement);
}
}
protected virtual void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
ElementPropertyChanged?.Invoke(this, e);
if (e.IsOneOf(Slider.ValueProperty, Slider.MinimumProperty, Slider.MaximumProperty))
UpdateValue();
else if (e.IsOneOf(VisualElement.BackgroundColorProperty, Slider.MaximumTrackColorProperty, Slider.MinimumTrackColorProperty, Slider.ThumbColorProperty))
UpdateColors();
}
public override bool OnTouchEvent(MotionEvent e)
{
if (_visualElementRenderer.OnTouchEvent(e) || base.OnTouchEvent(e))
return true;
return _motionEventHelper.HandleMotionEvent(Parent, e);
}
void UpdateColors()
{
if (Element == null || Control == null)
return;
Color backgroundColor = Element.MaximumTrackColor;
if (backgroundColor == Color.Default)
backgroundColor = Element.BackgroundColor;
Color progressColor = Element.MinimumTrackColor;
Color thumbColor = Element.ThumbColor;
this.ApplySeekBarColors(progressColor, backgroundColor, thumbColor);
}
void UpdateValue()
{
_min = Element.Minimum;
_max = Element.Maximum;
Value = Element.Value;
}
// SeekBar.IOnSeekBarChangeListener
void SeekBar.IOnSeekBarChangeListener.OnProgressChanged(SeekBar seekBar, int progress, bool fromUser)
{
if (fromUser)
((IElementController)Element).SetValueFromRenderer(Slider.ValueProperty, Value);
}
void SeekBar.IOnSeekBarChangeListener.OnStartTrackingTouch(SeekBar seekBar)
{
((ISliderController)Element)?.SendDragStarted();
}
void SeekBar.IOnSeekBarChangeListener.OnStopTrackingTouch(SeekBar seekBar)
{
((ISliderController)Element)?.SendDragCompleted();
}
// IVisualElementRenderer
VisualElement IVisualElementRenderer.Element => Element;
VisualElementTracker IVisualElementRenderer.Tracker => _visualElementTracker;
ViewGroup IVisualElementRenderer.ViewGroup => null;
AView IVisualElementRenderer.View => this;
SizeRequest IVisualElementRenderer.GetDesiredSize(int widthConstraint, int heightConstraint)
{
Measure(widthConstraint, heightConstraint);
return new SizeRequest(new Size(Control.MeasuredWidth, Control.MeasuredHeight), new Size());
}
void IVisualElementRenderer.SetElement(VisualElement element) =>
Element = (element as Slider) ?? throw new ArgumentException($"Element must be of type {nameof(Slider)}.");
void IVisualElementRenderer.SetLabelFor(int? id)
{
if (_defaultLabelFor == null)
_defaultLabelFor = ViewCompat.GetLabelFor(this);
ViewCompat.SetLabelFor(this, (int)(id ?? _defaultLabelFor));
}
void IVisualElementRenderer.UpdateLayout() =>
_visualElementTracker?.UpdateLayout();
// IViewRenderer
void IViewRenderer.MeasureExactly() =>
ViewRenderer.MeasureExactly(this, Element, Context);
// ITabStop
AView ITabStop.TabStop => this;
}
}
#endif

Просмотреть файл

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@android:color/white"
android:alpha="?android:attr/disabledAlpha" />
</selector>

Просмотреть файл

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
From original drawable https://github.com/aosp-mirror/platform_frameworks_base/blob/master/core/res/res/drawable/progress_horizontal_material.xml
with removed rounded corners. And, following some of the drawable/color links.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background"
android:gravity="center_vertical|fill_horizontal">
<shape android:shape="rectangle"
android:tint="?android:attr/colorControlNormal">
<corners android:radius="0dp" />
<solid android:color="@color/white_disabled_material" />
</shape>
</item>
<item android:id="@android:id/secondaryProgress"
android:gravity="center_vertical|fill_horizontal">
<scale android:scaleWidth="100%">
<shape android:shape="rectangle"
android:tint="?android:attr/colorControlActivated">
<corners android:radius="0dp" />
<solid android:color="@color/white_disabled_material" />
</shape>
</scale>
</item>
<item android:id="@android:id/progress"
android:gravity="center_vertical|fill_horizontal">
<scale android:scaleWidth="100%">
<shape android:shape="rectangle"
android:tint="?android:attr/colorControlActivated">
<corners android:radius="0dp" />
<solid android:color="@android:color/white" />
</shape>
</scale>
</item>
</layer-list>

Просмотреть файл

@ -6,12 +6,19 @@
<item name="materialButtonStyle">@style/XamarinFormsMaterialButton</item>
</style>
<!-- Material Sliders -->
<style name="XamarinFormsMaterialSlider" parent="Widget.AppCompat.SeekBar">
</style>
<!-- Material Progress Bars -->
<style name="XamarinFormsMaterialProgressBarHorizontal" parent="Widget.AppCompat.ProgressBar.Horizontal">
<item name="android:indeterminateOnly">false</item>
<item name="android:progressDrawable">@drawable/MaterialProgressBar</item>
</style>
<style name="XamarinFormsMaterialProgressBarCircular" parent="Widget.AppCompat.ProgressBar">
<item name="android:background">@drawable/MaterialActivityIndicatorBackground</item>
</style>
<!-- Material Buttons (All Styles) -->
<style name="XamarinFormsMaterialButton" parent="Widget.MaterialComponents.Button">
<item name="android:insetTop">0dp</item>
@ -23,4 +30,5 @@
<style name="XamarinFormsMaterialEntryFilled" parent="Widget.MaterialComponents.TextInputLayout.FilledBox">
<item name="boxCollapsedPaddingTop">8dp</item>
</style>
</resources>

Просмотреть файл

@ -315,6 +315,8 @@
<Compile Include="ButtonElementManager.cs" />
<Compile Include="IButtonLayoutRenderer.cs" />
<Compile Include="ButtonLayoutManager.cs" />
<Compile Include="Material\MaterialSliderRenderer.cs" />
<AndroidResource Include="Resources\color\white_disabled_material.xml" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
@ -403,6 +405,14 @@
<SubType>Designer</SubType>
</AndroidResource>
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\MaterialProgressBar.xml">
<SubType>Designer</SubType>
</AndroidResource>
</ItemGroup>
<ItemGroup>
<Folder Include="Resources\color\" />
</ItemGroup>
<Target Name="BeforeBuild" Condition=" '$(CreateAllAndroidTargets)' == 'true' ">
<!-- create 8.1 binaries-->
<MSBuild Targets="Restore" Projects="@(ProjectToBuild)">