右侧和文本上方的图标选择器 - Android

问题描述 投票:0回答:2

我在Xamarin Forms项目中通过这个精彩的post在右侧成功实现了带有向下图标的选择器,但是当选择器中的文本很长(比选择器控件的宽度)时,文本与向下的图像重叠,这看起来非常糟糕。

基本上,向下图标可绘制图像被设置为背景可绘制,所以我尝试在自定义渲染器中使用Control.Foreground,但是我得到了这个错误 - “Java.Lang.LinkageError:没有非静态方法”。

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

请协助。如果你指出文本省略号的任何解决方案(即...,像iOS这样的选择器中的长文本点)会非常有用,在此先感谢

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

android xamarin picker foreground bringtofront
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;

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

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

}

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代码来处理我的情况,因为我的下拉数量非常少,也因为我没有任何其他方法可以解决这个问题。

© www.soinside.com 2019 - 2024. All rights reserved.