0

我成功地实现了与Xamarin Forms项目的精彩帖子的右侧图标的Picker,但是当Picker中的文本长度(比Picker控件的宽度)时,文本与Down Image相重叠,看起来非常糟糕。

基本上向下图标可绘制图像设置为背景可绘制,因此我尝试在自定义渲染器中使用 Control.Foreground,但出现此错误 - “Java.Lang.LinkageError: no non-static method”。

...
if (Control != null && this.Element != null && !string.IsNullOrEmpty(element.Image))
              Control.Background = AddPickerStyles(element.Image);
...

请协助。如果您还指出文本省略号的任何解决方案(例如,iOS 等选择器中长文本的点),这将非常有帮助 提前致谢

注意:这在 iOS 中显然不是问题。

4

2 回答 2

0

是的,正如 LandLu 所说,您可以添加SetPadding来解决这个问题:

if (Control != null && this.Element != null && !string.IsNullOrEmpty(element.Image))
{
    Control.Background = AddPickerStyles(element.Image);

    Control.SetPadding(5, 0, 70, 0); //Add code here
}

或修改AddPickerStyles方法:

public LayerDrawable AddPickerStyles(string imagePath)
    {
        ShapeDrawable border = new ShapeDrawable();
        border.Paint.Color = Android.Graphics.Color.Gray;
        border.SetPadding(10,10,10,10);
        border.Paint.SetStyle(Paint.Style.Stroke);

        Drawable[] layers = { border , GetDrawable(imagePath) };
        LayerDrawable layerDrawable = new LayerDrawable(layers);
        layerDrawable.SetLayerInset(0, 0, 0, 0, 0);

        layerDrawable.SetPadding(5,0,70,0); // Add code here

        return layerDrawable;
    }

但这为 Moto E 等较小分辨率设备和 Nexus 9 等较大分辨率设备平板电脑隐藏了大量文本。任何解决方案..

如果您的意思是弹出对话框视图隐藏部分文本,下面是一种解决方法。您可以自定义弹出对话框,让对话框居中。

IElementController ElementController => Element as IElementController;
private AlertDialog _dialog;

修改对话框,需要自定义控件点击方法:

if (Control != null && this.Element != null && !string.IsNullOrEmpty(element.Image))
{
  ...
  Control.Click += Control_Click
}
...
 private void Control_Click(object sender, EventArgs e)
 {
     var picker = new NumberPicker(Context);
     picker.DescendantFocusability = DescendantFocusability.BlockDescendants;
     if (model.Items != null && model.Items.Any())
     {
        // set style here
        picker.MaxValue = model.Items.Count - 1;
        picker.MinValue = 0;
        //picker.SetBackgroundColor(Android.Graphics.Color.Yellow);
        picker.SetDisplayedValues(model.Items.ToArray());
        picker.WrapSelectorWheel = false;
        picker.Value = model.SelectedIndex;
      }

      var layout = new LinearLayout(Context) { Orientation = Orientation.Vertical };
      layout.AddView(picker);

     ElementController.SetValueFromRenderer(VisualElement.IsFocusedProperty, true);

      var builder = new AlertDialog.Builder(Context);
      builder.SetView(layout);

      builder.SetTitle(model.Title ?? "");
      builder.SetNegativeButton("Cancel  ", (s, a) =>
      {
     ElementController.SetValueFromRenderer(VisualElement.IsFocusedProperty, false);
         // It is possible for the Content of the Page to be changed when Focus is changed.
         // In this case, we'll lose our Control.
         Control?.ClearFocus();
        _dialog = null;
       });
       builder.SetPositiveButton("Ok ", (s, a) =>
       {
        ElementController.SetValueFromRenderer(Picker.SelectedIndexProperty, picker.Value);
        // It is possible for the Content of the Page to be changed on SelectedIndexChanged.
        // In this case, the Element & Control will no longer exist.
          if (Element != null)
           {
               if (model.Items.Count > 0 && Element.SelectedIndex >= 0)
                Control.Text = model.Items[Element.SelectedIndex];

     ElementController.SetValueFromRenderer(VisualElement.IsFocusedProperty, false);
                // It is also possible for the Content of the Page to be changed when Focus is changed.
                // In this case, we'll lose our Control.
                Control?.ClearFocus();
             }
            _dialog = null;
        });

     _dialog = builder.Create();
     _dialog.DismissEvent += (ssender, args) =>
      {
    ElementController?.SetValueFromRenderer(VisualElement.IsFocusedProperty, false);
      };
     _dialog.Show();
     var metrics = Resources.DisplayMetrics;
     Window dialogWindow = _dialog.Window;
     WindowManagerLayoutParams p = dialogWindow.Attributes; 
        // set width
     p.Width = metrics.WidthPixels;
     p.Gravity = GravityFlags.Center;
     p.Alpha = 0.8f;
     dialogWindow.Attributes = p;
 }

最后是以上两个问题的完整解法代码:

public class CustomPickerRenderer : PickerRenderer
{
    CustomPicker element;

    IElementController ElementController => Element as IElementController;
    private AlertDialog _dialog;
    protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
    {
        base.OnElementChanged(e);

        element = (CustomPicker)this.Element;

        if (Control != null && this.Element != null && !string.IsNullOrEmpty(element.Image))
        {
            Control.Background = AddPickerStyles(element.Image);
            //Control.SetPadding(5, 0, 70, 0);
            Control.Click += Control_Click;

        }
    }

    private void Control_Click(object sender, EventArgs e)
    {
        //throw new NotImplementedException();
        Picker model = Element;

        var picker = new NumberPicker(Context);
        picker.DescendantFocusability = DescendantFocusability.BlockDescendants;
        if (model.Items != null && model.Items.Any())
        {
            // set style here
            picker.MaxValue = model.Items.Count - 1;
            picker.MinValue = 0;
            //picker.SetBackgroundColor(Android.Graphics.Color.Yellow);
            picker.SetDisplayedValues(model.Items.ToArray());
            picker.WrapSelectorWheel = false;
            picker.Value = model.SelectedIndex;
        }

        var layout = new LinearLayout(Context) { Orientation = Orientation.Vertical };
        layout.AddView(picker);

        ElementController.SetValueFromRenderer(VisualElement.IsFocusedProperty, true);

        var builder = new AlertDialog.Builder(Context);
        builder.SetView(layout);

        builder.SetTitle(model.Title ?? "");
        builder.SetNegativeButton("Cancel  ", (s, a) =>
        {
            ElementController.SetValueFromRenderer(VisualElement.IsFocusedProperty, false);
            // It is possible for the Content of the Page to be changed when Focus is changed.
            // In this case, we'll lose our Control.
            Control?.ClearFocus();
            _dialog = null;
        });
        builder.SetPositiveButton("Ok ", (s, a) =>
        {
            ElementController.SetValueFromRenderer(Picker.SelectedIndexProperty, picker.Value);
            // It is possible for the Content of the Page to be changed on SelectedIndexChanged.
            // In this case, the Element & Control will no longer exist.
            if (Element != null)
            {
                if (model.Items.Count > 0 && Element.SelectedIndex >= 0)
                    Control.Text = model.Items[Element.SelectedIndex];
                ElementController.SetValueFromRenderer(VisualElement.IsFocusedProperty, false);
                // It is also possible for the Content of the Page to be changed when Focus is changed.
                // In this case, we'll lose our Control.
                Control?.ClearFocus();
            }
            _dialog = null;
        });

        _dialog = builder.Create();
        _dialog.DismissEvent += (ssender, args) =>
        {
            ElementController?.SetValueFromRenderer(VisualElement.IsFocusedProperty, false);
        };
        _dialog.Show();


        var metrics = Resources.DisplayMetrics;
        Window dialogWindow = _dialog.Window;
        WindowManagerLayoutParams p = dialogWindow.Attributes; 
        // set width
        p.Width = metrics.WidthPixels;
        p.Gravity = GravityFlags.Center;
        p.Alpha = 0.8f;
        dialogWindow.Attributes = p;
    }


    public LayerDrawable AddPickerStyles(string imagePath)
    {
        ShapeDrawable border = new ShapeDrawable();
        border.Paint.Color = Android.Graphics.Color.Gray;
        border.SetPadding(10,10,10,10);
        border.Paint.SetStyle(Paint.Style.Stroke);

        Drawable[] layers = { border , GetDrawable(imagePath) };
        LayerDrawable layerDrawable = new LayerDrawable(layers);
        layerDrawable.SetLayerInset(0, 0, 0, 0, 0);

        layerDrawable.SetPadding(5,0,80,0);

        return layerDrawable;
    }

    private BitmapDrawable GetDrawable(string imagePath)
    {
        int resID = Resources.GetIdentifier(imagePath, "drawable", this.Context.PackageName);
        var drawable = ContextCompat.GetDrawable(this.Context, resID);
        var bitmap = ((BitmapDrawable)drawable).Bitmap;

        var result = new BitmapDrawable(Resources, Bitmap.CreateScaledBitmap(bitmap, 70, 70, true));
        result.Gravity = Android.Views.GravityFlags.Right;

        return result;
    }

    protected override void Dispose(bool disposing)
    {
        Control.Click -= Control_Click;
        base.Dispose(disposing);
    }

}
于 2019-04-24T09:55:41.030 回答
0

我最终使用了一个网格,该网格在 xamarin 论坛讨论中给出的每列中都有一个选择器和图像。这很好用!

<Grid>
   <Grid.ColumnDefinitions>
      <ColumnDefinition Width="1*"/>
   </Grid.ColumnDefinitions>
   <userControl:BindablePicker Grid.Row="0" Grid.Column="0" ItemsSource="{Binding x, Mode=TwoWay}" SelectedItem="{Binding x}"/>
   <Image Grid.Row="0" Grid.Column="0" Source="arrow.png" HeightRequest="x" WidthRequest="x" InputTransparent="True" HorizontalOptions="End" VerticalOptions="Center"/>
</Grid>

注意:我在我的案例中使用了上面的 XAML 代码,因为我的下拉菜单数量很少,也因为我没有任何其他方法来克服这个问题。

于 2019-06-26T15:34:50.157 回答