有没有人有Xamarin Forms android按钮自定义渲染器的完整示例?或者甚至可能吗?
我基本上想要制作圆角按钮。
我尝试从这个例子开始: https://developer.xamarin.com/guides/xamarin-forms/application-fundamentals/custom-renderer/entry/
使用http://taoffi.isosoft.org/post/2016/03/26/Xamarin-forms-so-you-lost-your-rounded-buttons
但是我在编译时遇到了很多错误:
using System;
using System.Collections.Generic;
using System.Linq;
//using UXDivers.Artina.Shared;
using Xamarin.Forms;
using Android.Graphics.Drawables;
using System.ComponentModel;
using Xamarin.Forms.Platform.Android;
using Android.Graphics;
using Android.Views;
using System.Runtime.Remoting.Contexts;
using CustomRenderer.Android;
[assembly: ExportRenderer(typeof(Button), typeof(CustomButtonCompatRenderer))]
namespace CustomRenderer.Android
{
public class CustomButtonCompatRenderer : ButtonRenderer
{
public CustomButtonCompatRenderer(Context context) : base(context)
{
SetWillNotDraw(false);
}
private GradientDrawable _normal,
_pressed;
// resolves: button text alignment lost after click or IsEnabled change
//public override void ChildDrawableStateChanged(Android.Views.View child)
//{
// base.ChildDrawableStateChanged(child);
// Control.Text = Control.Text;
//}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Button> e)
{
base.OnElementChanged(e);
if (Control != null)
{
SetAlignment();
var density = Math.Max(1, Resources.DisplayMetrics.Density);
var button = e.NewElement;
var mode = MeasureSpec.GetMode((int)button.BorderRadius);
var borderRadius = button.BorderRadius * density;
var borderWidth = button.BorderWidth * density;
// Create a drawable for the button's normal state
_normal = new Android.Graphics.Drawables.GradientDrawable();
if (button.BackgroundColor.R == -1.0 && button.BackgroundColor.G == -1.0 && button.BackgroundColor.B == -1.0)
_normal.SetColor(Android.Graphics.Color.ParseColor("#ff2c2e2f"));
else
_normal.SetColor(button.BackgroundColor.ToAndroid());
_normal.SetStroke((int)borderWidth, button.BorderColor.ToAndroid());
_normal.SetCornerRadius(borderRadius);
// Create a drawable for the button's pressed state
_pressed = new Android.Graphics.Drawables.GradientDrawable();
var highlight = Context.ObtainStyledAttributes(new int[]
{
Android.Resource.Attribute.ColorAccent // .ColorActivatedHighlight
}).GetColor(0, Android.Graphics.Color.Gray);
_pressed.SetColor(highlight);
_pressed.SetStroke((int)borderWidth, button.BorderColor.ToAndroid());
_pressed.SetCornerRadius(borderRadius);
// Add the drawables to a state list and assign the state list to the button
var sld = new StateListDrawable();
sld.AddState(new int[] { Android.Resource.Attribute.StatePressed }, _pressed);
sld.AddState(new int[] { }, _normal);
Control.SetBackground(sld); //.SetBackgroundDrawable(sld); // deprecated
}
}
private void SetAlignment()
{
var element = this.Element as Button;
if (element == null || this.Control == null)
{
return;
}
this.Control.Gravity = GravityFlags.CenterHorizontal | GravityFlags.CenterVertical;
//element.VerticalAlignment.ToDroidVerticalGravity() |
//element.HorizontalAlignment.ToDroidHorizontalGravity();
}
void DrawCustom(Button targetButton)
{
if (Control == null || targetButton == null)
return;
}
}
}
错误:
CustomButtonCompatRenderer.cs(20,62,20,66): error CS1729: 'ButtonRenderer' does not contain a constructor that takes 1 arguments
CustomButtonCompatRenderer.cs(52,39,52,47): error CS0234: The type or namespace name 'Graphics' does not exist in the namespace 'CustomRenderer.Android' (are you missing an assembly reference?)
CustomButtonCompatRenderer.cs(55,38,55,54): error CS0234: The type or namespace name 'Graphics' does not exist in the namespace 'CustomRenderer.Android' (are you missing an assembly reference?)
CustomButtonCompatRenderer.cs(63,40,63,48): error CS0234: The type or namespace name 'Graphics' does not exist in the namespace 'CustomRenderer.Android' (are you missing an assembly reference?)
CustomButtonCompatRenderer.cs(66,68,66,79): error CS0117: 'Resource.Attribute' does not contain a definition for 'ColorAccent'
CustomButtonCompatRenderer.cs(67,52,67,68): error CS0234: The type or namespace name 'Graphics' does not exist in the namespace 'CustomRenderer.Android' (are you missing an assembly reference?)
CustomButtonCompatRenderer.cs(75,69,75,81): error CS0117: 'Resource.Attribute' does not contain a definition for 'StatePressed'
我的环境:
Visual Studio for mac:7.3.3(build 12)
Android SDK工具26.1.1
Android SDK构建工具26.0.3
Android SDK构建工具25.0.3
Android目标版:Android 7.1(API 25)
最低Android版本:Android 4.0.3(API 15)
PS:我是Xamarin和C#的新手
答案 0 :(得分:2)
在这里。带有CornerRadius和Padding的启用波纹的按钮。
您必须添加使用,命名空间和ExportRenderer
属性。
MainActivity.Activity是我在应用初始化时设置的Context
类型的属性。只需在Forms.Init。
Activity = this;
public class ButtonRenderer : Xamarin.Forms.Platform.Android.ButtonRenderer
{
// Your Button class
Button button;
float radius = 0;
//--------------------------------------------------------------------------------//
public ButtonRenderer() : base(MainActivity.Activity) { }
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Button> e)
{
base.OnElementChanged(e);
button = Element as Button;
if (e.OldElement == null)
{
if (IsPostLollipopAndroid) Control.Elevation = 2;
radius = (float)button.CornerRadius;
if (button.Padding != null)
{
Control.SetPadding(ToPx((int)button.Padding.Left), ToPx((int)button.Padding.Top), ToPx((int)button.Padding.Right), ToPx((int)button.Padding.Bottom));
}
SetColors();
Control.SetMinHeight(0);
Control.SetMinimumHeight(0);
Control.SetMinWidth(0);
Control.SetMinimumWidth(0);
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
switch (e.PropertyName)
{
case nameof(VisualElement.BackgroundColor):
case nameof(Button.PressedColor):
{
SetColors();
break;
}
case nameof(Button.Padding):
{
if (button.Padding != null)
{
Control.SetPadding((int)button.Padding.Left, (int)button.Padding.Top, (int)button.Padding.Right, (int)button.Padding.Bottom);
}
break;
}
}
}
public override bool DispatchTouchEvent(MotionEvent e)
{
if (!Element.InputTransparent) return base.DispatchTouchEvent(e);
else return true;
}
void SetColors()
{
radius = (float)button.CornerRadius;
StateListDrawable list = new StateListDrawable();
if (IsPreLollipopAndroid)
{
GradientDrawable pressedDrawable;
if (Element.BackgroundColor != Color.Transparent)
{
Android.Graphics.Color pressedColor = ChangeColorBrightness(Element.BackgroundColor, (button.PressedColor == ButtonPressedColor.Dark) ? 1f - (float).15 : 1f + (float).15).ToAndroid();
pressedDrawable = new GradientDrawable(GradientDrawable.Orientation.LeftRight, new int[] { pressedColor, pressedColor });
pressedDrawable.SetCornerRadius(ToPxFloat(radius));
}
else
{
Android.Graphics.Color pressedColor = (button.PressedColor == ButtonPressedColor.Dark) ? Color.Black.MultiplyAlpha(.15).ToAndroid() : Color.White.MultiplyAlpha(.15).ToAndroid();
pressedDrawable = new GradientDrawable(GradientDrawable.Orientation.LeftRight, new int[] { pressedColor, pressedColor });
pressedDrawable.SetCornerRadius(ToPxFloat(radius));
}
list.AddState(new int[] { Android.Resource.Attribute.StatePressed }, pressedDrawable);
//--------------------------------------------------------------------------------//
Android.Graphics.Color color = Element.BackgroundColor.ToAndroid();
var normalDrawable = new GradientDrawable(GradientDrawable.Orientation.LeftRight, new int[] { color, color });
normalDrawable.SetCornerRadius(ToPxFloat(radius));
list.AddState(new int[] { -Android.Resource.Attribute.StatePressed }, normalDrawable);
Control.Background = list;
}
else
{
GradientDrawable normalDrawable = new GradientDrawable();
normalDrawable.SetCornerRadius(ToPxFloat(radius));
normalDrawable.SetColor(Element.BackgroundColor.ToAndroid());
float[] outerRadii = Enumerable.Repeat(ToPxFloat(radius), 8).ToArray();
RoundRectShape r = new RoundRectShape(outerRadii, null, null);
ShapeDrawable shapeDrawable = new ShapeDrawable(r);
shapeDrawable.Paint.Color = Color.White.ToAndroid();
var pressedColor = (button.PressedColor == ButtonPressedColor.Dark) ? Color.Black.MultiplyAlpha(.15).ToAndroid() : Color.White.MultiplyAlpha(.15).ToAndroid();
var ripple = new RippleDrawable(ColorStateList.ValueOf(pressedColor), normalDrawable, shapeDrawable);
Control.Background = ripple;
}
}
public static int ToPx(double dp)
{
return (int)Android.Util.TypedValue.ApplyDimension(Android.Util.ComplexUnitType.Dip, (float)dp, Droid.MainActivity.Activity.Resources.DisplayMetrics);
}
public static float ToPxFloat(double dp)
{
return Android.Util.TypedValue.ApplyDimension(Android.Util.ComplexUnitType.Dip, (float)dp, Droid.MainActivity.Activity.Resources.DisplayMetrics);
}
public static bool IsPreLollipopAndroid => Android.OS.Build.VERSION.SdkInt < Android.OS.BuildVersionCodes.Lollipop;
public static bool IsPostLollipopAndroid => Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Lollipop;
public static Color ChangeColorBrightness(Color color, float factor)
{
return Color.FromRgba(color.R * factor, color.G * factor, color.B * factor, color.A);
}
}
Button类有Padding,CornerRadius和PressedColor(包含Dark
和Light
字段的枚举。)
希望它有所帮助!