最近我一直对创建Android和iOS的自定义控件感兴趣,但也希望它们可以在Xamarin Forms中使用 . 这怎么可能?表格是否在幕后做了一些非常奇怪的事情?如何在堆叠布局或网格中进行大小调整?

作为一个非常简单的例子,Pluralsighti上的一个教程已经跟随自定义android控件创建了一个“lengthpicker”控件 . 它包括2个按钮和一个文本视图 .

Resources\layout\length_picker.axml

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
    <Button
        android:id="@+id/minus_button"
        android:text="-"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <TextView
        android:id="@+id/text"
        android:layout_width="96dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:gravity="center"
        android:textAppearance="@android:style/TextAppearance.Large" />
    <Button
        android:id="@+id/plus_button"
        android:text="+"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</merge>

LengthPicker.cs

public class LengthPicker : LinearLayout
{
    private View mPlusButton;
    private TextView mTextView;
    private View mMinusButton;

    private int mNumInches = 0;

    public LengthPicker(Context context) :base(context)
    {
        Init();
    }

    public LengthPicker(Context context, IAttributeSet attrs): base(context, attrs)
    {
        Init();
    }

    private void Init()
    {
        LayoutInflater inflater = LayoutInflater.From(Context);
        inflater.Inflate(Resource.Layout.length_picker,this);

        mPlusButton = FindViewById<Button>(Resource.Id.plus_button);
        mTextView = FindViewById<TextView>(Resource.Id.text);
        mMinusButton = FindViewById<Button>(Resource.Id.minus_button);

        UpdateControls();
        ApplyButtonClickHandlers();

        Orientation = Orientation.Horizontal;

        this.LayoutParameters = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WrapContent, ViewGroup.LayoutParams.WrapContent);
    }

    private void ApplyButtonClickHandlers()
    {
        mPlusButton.Click += MPlusButton_Click;
        mMinusButton.Click += MMinusButton_Click;
    }

    private void UpdateControls()
    {
        int feet = mNumInches / 12;
        int inches = mNumInches % 12;

        string text = $"{feet}' {inches}\"";
        if(feet == 0)
        {
            text = $"{inches}\"";
        }
        else
        {
            if(inches == 0)
            {
                text = $"{feet}'";
            }
        }

        mTextView.Text = text;

        mMinusButton.Enabled = mNumInches > 0;
    }

    private void MMinusButton_Click(object sender, EventArgs e)
    {
        mNumInches--;
        UpdateControls();
    }

    private void MPlusButton_Click(object sender, EventArgs e)
    {
        mNumInches++;
        UpdateControls();
    }
}

如何将此转换为Xamarin Forms可用控件?我试图这样做并且它有效(有一些小的警告,但我仍然不知道我是否正在做“对”

我在PCL中有一个从View扩展的类 . PCL LengthPicker.cs

public class LengthPicker : Xamarin.Forms.View
{
    public static readonly BindableProperty MinusColorProperty = BindableProperty.Create("MinusColor", typeof(Color), typeof(LengthPicker), Color.Default);
    public Color MinusColor
    {
        get { return (Color)GetValue(MinusColorProperty); }
        set { SetValue(MinusColorProperty, value); }
    }
}

在android项目中,我有一个扩展 LengthPickerRenderer.cs 的CustomRenderer

using ALengthPicker = MobileControls.Samples.LengthPicker; // LengthPicker in separater Android class library
using AButton = Android.Widget.Button;
using ATextView = Android.Widget.TextView;

namespace FormsMobileControlApp.Droid.Renderers
{


    public class LengthPickerRenderer :ViewRenderer<LengthPicker,ALengthPicker>
    {
        private AButton _minusButton;
        private AButton _plusButton;
        private ATextView _text;

        protected override void OnElementChanged(ElementChangedEventArgs<Controls.LengthPicker> e)
        {
            base.OnElementChanged(e);
            if (e.OldElement == null)
            {
                if (Control == null)
                    SetNativeControl(new ALengthPicker(Forms.Context));

                _minusButton = Control.FindViewById<AButton>(MobileControls.Resource.Id.minus_button);
                _text = Control.FindViewById<ATextView>(MobileControls.Resource.Id.text);
                _plusButton = Control.FindViewById<AButton>(MobileControls.Resource.Id.plus_button);
            }

            . . .

        }
    }
}

现在,就像我说的那样有效,但有一些奇怪的事情发生了,我也不知道这是否“正确” . 1.)lengthpicker的教程有控件XML将它的根作为合并 . 这在XF中使用时效果不佳,因此我将其更改为LinearLayout 2.)具有类似Color的按钮的可绑定属性是很奇怪的 . 为了更改自定义渲染器上的背景颜色,我必须调用_minusButton.SetBackground(Element.MinusColor.ToAndroid()),这使得按钮看起来非常扁平,甚至比其他xamarin表单按钮更大

我在android上看到了关于自定义xamarin表单控件的James Montemagno's blog post但它没有对膨胀布局做任何事情,而是覆盖了draw方法 .

有没有经验做过这样的事情?