【问题标题】:Picker with down icon on the right and over the text - Android右侧和文本上方带有向下图标的选取器 - Android
【发布时间】:2019-09-11 15:02:19
【问题描述】:

I successfully implemented the picker with down icon on the right from this wonderful post in Xamarin Forms project, but when the text in picker is long (than the picker control's width), the text与向下的图像重叠,看起来很糟糕。

基本上向下图标可绘制图像设置为背景可绘制,所以我尝试在自定义渲染器中使用 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 中显然不是问题。

【问题讨论】:

  • 检查是否可以在 CustomPicker 中添加一些填充
  • @Karan,谢谢..我在 xamarin 论坛forums.xamarin.com/discussion/comment/372139得到了同样的答案@
  • @PaulsonMaclean 如果问题解决了,有空的时候标记答案:)

标签: android xamarin picker foreground bringtofront


【解决方案1】:

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

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

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

}

【讨论】:

  • 但这为 Moto E 等较小分辨率设备和 Nexus 9 等较大分辨率设备平板电脑隐藏了大量文本。任何解决方案..?
  • @PaulsonMaclean 你的意思是弹出视图或条目视图不能显示全部内容吗?你可以显示图像,我已经更新了答案。感谢您的回复。 :)
  • 警告,完整的解决方案在 Android this question。
【解决方案2】:

我最终使用了一个网格,该网格在 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 代码,因为我的下拉菜单数量很少,也因为我没有任何其他方法来解决这个问题。

【讨论】:

  • 如果我点击箭头图像,它不会触发 Picker 功能
猜你喜欢
  • 1970-01-01
  • 2020-11-09
  • 1970-01-01
  • 1970-01-01
  • 2021-02-20
  • 2012-02-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多