右侧和文本上方带有向下图标的选择器 - Android

Picker with down icon on the right and over the text - Android

我成功地实现了Xamarin forms Project的奇妙post的右侧图标的选择器, =25=], 文字和下图重叠, 看起来很糟糕

基本上向下图标可绘制图像设置为背景可绘制,所以我尝试在自定义渲染器中使用 Control.Foreground,但我遇到了这个错误 - "Java.Lang.LinkageError: no non-static method"。

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

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

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

是的,正如 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;
    }

But this is hiding a lot of text for smaller resolution devices like Moto E and larger resolution device tablets like Nexus 9.. Any solution..

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

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);
    }

}

我最终使用了一个网格,该网格在每列中都有一个选择器和图像,如 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 代码中使用了这个代码,因为我的下拉菜单数量很少,也因为我没有任何其他方法来克服这个问题问题。