【问题标题】:Xamarin Forms android button custom rendererXamarin Forms android 按钮自定义渲染器
【发布时间】:2018-07-23 16:20:22
【问题描述】:

有人有 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(内部版本 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# 的新手

【问题讨论】:

    标签: c# xamarin.forms xamarin.android


    【解决方案1】:

    来了。带有 CornerRadius 和 Padding 的启用波纹的按钮。

    您必须添加 usings、命名空间和 ExportRenderer 属性。

    MainActivity.Activity 是我在应用初始化时设置的Context 类型的属性。只需在 OnCreate 方法中的 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(带有 DarkLight 字段的枚举)。

    希望对你有帮助!

    【讨论】:

    • 什么是“mainactivity.activity”。你能展示你的活动课吗?
    • 哦,对不起,我忘了...我会编辑答案
    猜你喜欢
    • 1970-01-01
    • 2018-07-29
    • 2016-09-03
    • 1970-01-01
    • 2018-03-15
    • 2021-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多