【问题标题】:Custom Renderer: Custom Renderer for rounded buttons自定义渲染器:圆形按钮的自定义渲染器
【发布时间】:2017-06-09 14:08:08
【问题描述】:

我正在使用 PCL Xamarin Forms Project 开发一个跨平台应用程序。我的应用将在 ios、android、windows 10 和 windows 8.1 桌面上运行。

我想为 xamarin 表单中的按钮控件制作一个自定义渲染器,在其中我可以从 xaml 页面和后面的代码中指定以下属性-

  1. 边框颜色
  2. 边框宽度
  3. 边界半径
  4. 背景颜色
  5. 文字颜色
  6. 文本字体大小、颜色、粗体等属性。
  7. 按钮的高度和宽度

我已经尝试过 xamarin 表单的普通按钮控件,但边框半径在 android 和 Windows 10 中的悬停按钮颜色更改中不起作用。 那么我该如何实现呢?

【问题讨论】:

  • 你有什么问题?
  • @Jason 我的问题你还不清楚吗?
  • “我需要...”不是问题。

标签: xamarin xamarin.forms portable-class-library custom-renderer


【解决方案1】:

我在我的应用程序上使用这些属性,对我来说效果很好。 我将这些属性与“样式”一起使用。

例子:

<Style x:Key="buttonStyle" TargetType="Button">
    <Setter Property="BackgroundColor" Value="{DynamicResource Snow}"/>
    <Setter Property="TextColor" Value="{DynamicResource LightBlue}" />
    <Setter Property="BorderColor" Value="{DynamicResource LightBlue}"/>
    <Setter Property="BorderRadius" Value="15"/>
    <Setter Property="BorderWidth" Value="1"/>
    <Setter Property="FontAttributes" Value="Bold" />
  </Style>

我的按钮:

<Button Text="Login" Command="{Binding LoginCommand}" Style="{DynamicResource buttonStyle}" />

Xamarin Styles

【讨论】:

  • 我已经尝试过了,但在 android 中它不起作用。按钮没有边框,没有圆角
  • 尝试清除项目并再次编译。也许只是文件上的垃圾。我在我当前的项目中使用它,我没有问题。
  • 我试试这个,得到错误:命名空间前缀'x'未定义
【解决方案2】:

在 Android 中,RadiusProperty 仅与 AppCompat 停止工作,它是 known issue

AppCompat

如果您想同时使用普通按钮和 AppCompat,则需要从 Button 继承并注册一个CustomRenderer

[assembly: ExportRenderer(typeof(RoundButton), typeof(RoundButtonRenderer))]
namespace Project.Droid.Renderers
{
    public class RoundButtonRenderer : Xamarin.Forms.Platform.Android.AppCompat.ButtonRenderer
    {
        ButtonDrawable _backgroundDrawable;
        Drawable _defaultDrawable;
        bool _drawableEnabled;

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_backgroundDrawable != null)
                {
                    _backgroundDrawable.Dispose();
                    _backgroundDrawable = null;
                }
            }

            base.Dispose(disposing);
        }


        protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Button> e)
        {
            base.OnElementChanged(e);

            if (e.OldElement != null && _drawableEnabled)
            {
                _drawableEnabled = false;
                _backgroundDrawable.Reset();
                _backgroundDrawable = null;
            }
            UpdateDrawable();
        }



        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (_drawableEnabled &&
                (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName || e.PropertyName == Xamarin.Forms.Button.BorderColorProperty.PropertyName || e.PropertyName == Xamarin.Forms.Button.BorderRadiusProperty.PropertyName ||
                e.PropertyName == Xamarin.Forms.Button.BorderWidthProperty.PropertyName))
            {
                _backgroundDrawable.Reset();
                Control.Invalidate();
            }

            base.OnElementPropertyChanged(sender, e);
        }

        private void UpdateDrawable()
        {
            if (Element.BackgroundColor == Color.Default)
            {
                if (!_drawableEnabled)
                    return;

                if (_defaultDrawable != null)
                    Control.SetBackground(_defaultDrawable);

                _drawableEnabled = false;
            }
            else
            {
                if (_backgroundDrawable == null)
                    _backgroundDrawable = new ButtonDrawable();

                _backgroundDrawable.Button = Element;

                if (_drawableEnabled)
                    return;

                if (_defaultDrawable == null)
                    _defaultDrawable = Control.Background;

                Control.SetBackground(_backgroundDrawable.GetDrawable());
                _drawableEnabled = true;
            }

            Control.Invalidate();
        }
    }


    public class ButtonDrawable : IDisposable
    {
        object _backgroundDrawable;

        PropertyInfo ButtonProperty;
        public Xamarin.Forms.Button Button
        {
            get
            {
                return (Xamarin.Forms.Button)ButtonProperty.GetMethod.Invoke(_backgroundDrawable, null);
            }
            set
            {
                ButtonProperty.SetMethod.Invoke(_backgroundDrawable, new object[] { value });
            }
        }

        public ButtonDrawable()
        {
            _backgroundDrawable = typeof(Xamarin.Forms.Platform.Android.ButtonRenderer).Assembly.CreateInstance("Xamarin.Forms.Platform.Android.ButtonDrawable");
            this.ResetMethod = _backgroundDrawable.GetType().GetMethod("Reset", BindingFlags.Instance | BindingFlags.Public);
            this.DisposeMethod = _backgroundDrawable.GetType().GetMethod("Dispose", BindingFlags.Instance | BindingFlags.Public);
            this.ButtonProperty = _backgroundDrawable.GetType().GetProperty("Button", BindingFlags.Instance | BindingFlags.Public);
        }

        MethodInfo ResetMethod;
        public void Reset()
        {
            ResetMethod.Invoke(_backgroundDrawable, null);
        }

        MethodInfo DisposeMethod;
        public void Dispose()
        {
            DisposeMethod.Invoke(_backgroundDrawable, null);
        }

        public Android.Graphics.Drawables.Drawable GetDrawable()
        {
            return _backgroundDrawable as Android.Graphics.Drawables.Drawable;
        }
    }
}

没有 AppCompat

如果你想删除 AppCompat,你必须做两件事

您的MainActivity 现在必须从global::Xamarin.Forms.Platform.Android.FormsApplicationActivity 继承 并且您通常在 resources/values/styles.xml 中的样式必须继承自非 AppCompat 样式,例如 android:Theme.Material

<resources>
  <!-- inherit from the material theme -->
  <style name="AppTheme" parent="android:Theme.Material">
    <!-- Main theme colors -->
    <!--   your app branding color for the app bar -->
    <item name="android:colorPrimary">@color/primary</item>
    <!--   darker variant for the status bar and contextual app bars -->
    <item name="android:colorPrimaryDark">@color/primary_dark</item>
    <!--   theme UI controls like checkboxes and text fields -->
    <item name="android:colorAccent">@color/accent</item>
  </style>
</resources>

【讨论】:

  • 边界半径是否适用于IOS?我还没试过。
  • 从来没有遇到过问题,但没有在任何windows平台上尝试过
  • 我试过Windows10和8.1的普通按钮控制效果很好!!!
  • @Sonali 如果您在BorderRadius 上输入的数量不正确,大于其高度的一半,则会有点错误
  • 好的,我会记住这一点,所以只为 android 制作一个自定义渲染器可以解决我的问题,对吧?
【解决方案3】:
  1. 在内容页面资源中创建样式并在按钮中添加此样式。
  2. CornerRadius 必须是 HeightRequest 和 WidthRequest 的一半。
  3. 这适用于 Xamarin.Forms >= 3.4。现在 BorderRadius 转换为 CornerRadius。
<ContentPage.Resources>
    <ResourceDictionary>
        <Style x:Key="myRoundbutton" TargetType="Button">
            <Setter Property="BackgroundColor" Value="Green"/>
            <Setter Property="TextColor" Value="White" />
            <Setter Property="BorderColor" Value="Blue"/>
             <Setter Property="CornerRadius" Value="35"/>
            <Setter Property="HeightRequest" Value="70" />
            <Setter Property="WidthRequest" Value="70"/>
            <Setter Property="BorderWidth" Value="2"/>
            <Setter Property="FontAttributes" Value="Bold" />
        </Style>
    </ResourceDictionary>
</ContentPage.Resources>

<ContentPage.Content>
      <StackLayout HorizontalOptions="Fill" 
                   VerticalOptions="Fill">

          <Button Image="myBtn3.png" 
                  Command="{Binding LoginCommand}" 
                  Style="{DynamicResource myRoundbutton}" />

      </StackLayout>
</ContentPage.Content>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-07-23
    • 2017-11-24
    • 2013-09-25
    • 2011-07-14
    • 1970-01-01
    • 1970-01-01
    • 2012-08-25
    • 1970-01-01
    相关资源
    最近更新 更多