2016-08-18 4 views
10

Piszę niestandardową nakładkę dla czytnika QR ZXinga. Oto działający przykład:Dlaczego ten sam interfejs jest renderowany inaczej na emulatorze i urządzeniu?

public partial class CustomScanPage : ContentPage 
{ 
    ZXingScannerView zxing; 
    private List<BoxView> _boxes; 


    public CustomScanPage() : base() 
    { 
     zxing = new ZXingScannerView 
     { 
      HorizontalOptions = LayoutOptions.FillAndExpand, 
      VerticalOptions = LayoutOptions.FillAndExpand 
     }; 
     zxing.OnScanResult += (result) => 
      Device.BeginInvokeOnMainThread(async() => 
      { 
       zxing.IsAnalyzing = false; 

       SetBoxesColor(Color.FromHex("#76ff03")); 
       await Task.Delay(2000); 

       await DisplayAlert("Scanned Barcode", result.Text, "OK"); 

       SetBoxesColor(Color.White); 
      }); 
     zxing.Options = new MobileBarcodeScanningOptions { 
      PossibleFormats = new List<ZXing.BarcodeFormat> { ZXing.BarcodeFormat.QR_CODE } 
     }; 
     var overlay = BuildGrid(); 

     var grid = new Grid 
     { 
      VerticalOptions = LayoutOptions.FillAndExpand, 
      HorizontalOptions = LayoutOptions.FillAndExpand, 
     }; 
     grid.Children.Add(zxing); 
     grid.Children.Add(overlay); 

     Content = grid; 
    } 

    protected override void OnAppearing() 
    { 
     base.OnAppearing(); 

     zxing.IsScanning = true; 
    } 

    protected override void OnDisappearing() 
    { 
     zxing.IsScanning = false; 

     base.OnDisappearing(); 
    } 

    private AbsoluteLayout BuildGrid() 
    { 
     var al = new AbsoluteLayout(); 
     var mask = new BoxView 
     { 
      HorizontalOptions = LayoutOptions.Fill, 
      VerticalOptions = LayoutOptions.Fill, 
      BackgroundColor = Color.Transparent 
     }; 

     var maskSide = 196; 

     var yBegin = Math.Round((App.ScreenHeight - maskSide)/2); 
     var xBegin = Math.Round((App.ScreenWidth - maskSide)/2); 
     var barLong = 40; 
     var barShort = 4; 
     var barColor = Color.White; 

     var grid = new Grid { ColumnSpacing = 0, RowSpacing = 0 }; 
     grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(yBegin, GridUnitType.Absolute) }); 
     grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(maskSide, GridUnitType.Absolute) }); 
     grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(App.ScreenHeight - yBegin, GridUnitType.Absolute) }); 
     grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(xBegin, GridUnitType.Absolute) }); 
     grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(maskSide, GridUnitType.Absolute) }); 
     grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(App.ScreenWidth - xBegin, GridUnitType.Absolute) }); 

     grid.Children.Add(new BoxView { HorizontalOptions = LayoutOptions.Fill, VerticalOptions = LayoutOptions.Fill, BackgroundColor = Color.FromHex("#80323232"), }, 0, 0); 
     grid.Children.Add(new BoxView { HorizontalOptions = LayoutOptions.Fill, VerticalOptions = LayoutOptions.Fill, BackgroundColor = Color.FromHex("#80323232") }, 0, 1); 
     grid.Children.Add(new BoxView { HorizontalOptions = LayoutOptions.Fill, VerticalOptions = LayoutOptions.Fill, BackgroundColor = Color.FromHex("#80323232") }, 0, 2); 

     grid.Children.Add(new BoxView { HorizontalOptions = LayoutOptions.Fill, VerticalOptions = LayoutOptions.Fill, BackgroundColor = Color.FromHex("#80323232") }, 1, 0); 
     grid.Children.Add(mask, 1, 1); 
     grid.Children.Add(new BoxView { HorizontalOptions = LayoutOptions.Fill, VerticalOptions = LayoutOptions.Fill, BackgroundColor = Color.FromHex("#80323232") }, 1, 2); 

     grid.Children.Add(new BoxView { HorizontalOptions = LayoutOptions.Fill, VerticalOptions = LayoutOptions.Fill, BackgroundColor = Color.FromHex("#80323232") }, 2, 0); 
     grid.Children.Add(new BoxView { HorizontalOptions = LayoutOptions.Fill, VerticalOptions = LayoutOptions.Fill, BackgroundColor = Color.FromHex("#80323232") }, 2, 1); 
     grid.Children.Add(new BoxView { HorizontalOptions = LayoutOptions.Fill, VerticalOptions = LayoutOptions.Fill, BackgroundColor = Color.FromHex("#80323232") }, 2, 2); 

     grid.HorizontalOptions = LayoutOptions.FillAndExpand; 
     grid.VerticalOptions = LayoutOptions.FillAndExpand; 

     AbsoluteLayout.SetLayoutBounds(grid, new Rectangle(0, 0, 1, 1)); 
     AbsoluteLayout.SetLayoutFlags(grid, AbsoluteLayoutFlags.All); 

     al.Children.Add(grid); 

     var b1 = new BoxView { HorizontalOptions = LayoutOptions.Fill, VerticalOptions = LayoutOptions.Fill, BackgroundColor = barColor }; 

     AbsoluteLayout.SetLayoutBounds(b1, new Rectangle(xBegin - barShort, yBegin, barShort, barLong - barShort)); 
     AbsoluteLayout.SetLayoutFlags(b1, AbsoluteLayoutFlags.None); 

     var b2 = new BoxView { HorizontalOptions = LayoutOptions.Fill, VerticalOptions = LayoutOptions.Fill, BackgroundColor = barColor }; 

     AbsoluteLayout.SetLayoutBounds(b2, new Rectangle(xBegin - barShort, yBegin - barShort, barLong, barShort)); 
     AbsoluteLayout.SetLayoutFlags(b2, AbsoluteLayoutFlags.None); 

     var b3 = new BoxView { HorizontalOptions = LayoutOptions.Fill, VerticalOptions = LayoutOptions.Fill, BackgroundColor = barColor }; 

     AbsoluteLayout.SetLayoutBounds(b3, new Rectangle(xBegin + maskSide, yBegin, barShort, barLong - barShort)); 
     AbsoluteLayout.SetLayoutFlags(b3, AbsoluteLayoutFlags.None); 

     var b4 = new BoxView { HorizontalOptions = LayoutOptions.Fill, VerticalOptions = LayoutOptions.Fill, BackgroundColor = barColor }; 

     AbsoluteLayout.SetLayoutBounds(b4, new Rectangle(xBegin - barLong + maskSide + barShort, yBegin - barShort, barLong, barShort)); 
     AbsoluteLayout.SetLayoutFlags(b4, AbsoluteLayoutFlags.None); 

     var b5 = new BoxView { HorizontalOptions = LayoutOptions.Fill, VerticalOptions = LayoutOptions.Fill, BackgroundColor = barColor }; 

     AbsoluteLayout.SetLayoutBounds(b5, new Rectangle(xBegin - barShort, yBegin + maskSide + barShort - barLong, barShort, barLong - barShort)); 
     AbsoluteLayout.SetLayoutFlags(b5, AbsoluteLayoutFlags.None); 

     var b6 = new BoxView { HorizontalOptions = LayoutOptions.Fill, VerticalOptions = LayoutOptions.Fill, BackgroundColor = barColor }; 

     AbsoluteLayout.SetLayoutBounds(b6, new Rectangle(xBegin - barShort, yBegin + maskSide, barLong, barShort)); 
     AbsoluteLayout.SetLayoutFlags(b6, AbsoluteLayoutFlags.None); 

     var b7 = new BoxView { HorizontalOptions = LayoutOptions.Fill, VerticalOptions = LayoutOptions.Fill, BackgroundColor = barColor }; 

     AbsoluteLayout.SetLayoutBounds(b7, new Rectangle(xBegin + maskSide - barLong + barShort, yBegin + maskSide, barLong, barShort)); 
     AbsoluteLayout.SetLayoutFlags(b7, AbsoluteLayoutFlags.None); 

     var b8 = new BoxView { HorizontalOptions = LayoutOptions.Fill, VerticalOptions = LayoutOptions.Fill, BackgroundColor = barColor }; 

     AbsoluteLayout.SetLayoutBounds(b8, new Rectangle(xBegin + maskSide, yBegin + maskSide - barLong + barShort, barShort, barLong - barShort)); 
     AbsoluteLayout.SetLayoutFlags(b8, AbsoluteLayoutFlags.None); 

     al.Children.Add(b1); 
     al.Children.Add(b2); 
     al.Children.Add(b3); 
     al.Children.Add(b4); 
     al.Children.Add(b5); 
     al.Children.Add(b6); 
     al.Children.Add(b7); 
     al.Children.Add(b8); 

     _boxes = new List<BoxView> { b1, b2, b3, b4, b5, b6, b7, b8 }; 

     return al; 
    } 

    private void SetBoxesColor(Color c) 
    { 
     foreach (var box in _boxes) 
     { 
      box.Color = c; 
     } 
    } 
} 

Jak widać, nic nie jest skomplikowane. Ale problem polega na tym, jak ta strona jest renderowana. Na urządzeniach Xamarin Android Player (Nexus 4 KitKat HD i Nexus 5 Lollipop Full HD) wszystko wygląda zgodnie z oczekiwaniami:

enter image description here

Jednak gdy uruchomię samej aplikacji (bez różowym tle na siatce) na moim Nexus 5x urządzenie (Marshmallow, Full HD), jak widać, piksele nie są precyzyjne, jest trochę niedopasowania w górnym prawym zielonym kształcie, trochę przesunięcia w lewych kształtach i jest jedno-pikselowa przezroczysta przerwa na siatce wiersz:

enter image description here

fakt, że kod jest poprawnie renderowane na dwóch urządzeniach pozwala mi sądzić, że moja arytmetyczna punktacja jest poprawna. Co może być problemem? I co ważniejsze, co mogę zrobić, aby go rozwiązać?

EDIT:

Może jakoś to dlatego, że pt/px stosunek mojego urządzenia jest inny niż stosunek devices emulator?

EDIT:

@ odpowiedź Cheesebaron było źle. Oto, co próbowałem zrobić, co nie pomogło: Stworzyłem CustomBoxView, CustomBoxViewNative, CustomBoxViewRenderer i użyłem CustomBoxView zamiast BoxView. To nie działa.

CustomBoxView:

public class CustomBoxView : View 
{ 
    public static readonly BindableProperty ColorProperty = BindableProperty.Create("Color", typeof (string), 
     typeof (CustomBoxView), "#FF0000"); 

    public string Color 
    { 
     get { return (string) GetValue(ColorProperty); } 
     set { SetValue(ColorProperty, value); } 
    } 
} 

CustomBoxViewNative:

public class CustomBoxViewNative : View 
{ 
    private Canvas _canvas; 
    private Rect _rect; 

    public CustomBoxViewNative(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer) 
    { 
    } 

    public CustomBoxViewNative(Context context) : base(context) 
    { 
    } 

    public CustomBoxViewNative(Context context, IAttributeSet attrs) : base(context, attrs) 
    { 
    } 

    public CustomBoxViewNative(Context context, IAttributeSet attrs, int defStyleAttr) : base(context, attrs, defStyleAttr) 
    { 
    } 

    public CustomBoxViewNative(Context context, IAttributeSet attrs, int defStyleAttr, int defStyleRes) : base(context, attrs, defStyleAttr, defStyleRes) 
    { 
    } 

    protected override void OnDraw(Canvas canvas) 
    { 
     var paintCircle = new Paint { Color = Color.White }; 
     paintCircle.StrokeWidth = Width*Resources.DisplayMetrics.Density; 
     _rect = new Rect(0, 0, Width, Height); 
     _canvas = canvas; 
     _canvas.DrawRect(_rect, paintCircle); 
    } 
} 

CustomBoxViewRenderer:

public class CustomBoxViewRenderer : ViewRenderer<CustomBoxView, CustomBoxViewNative> 
{ 
    protected override void OnElementChanged(ElementChangedEventArgs<CustomBoxView> e) 
    { 
     base.OnElementChanged(e); 

     if (e.OldElement != null || this.Element == null) 
      return; 

     var nativeControl = new CustomBoxViewNative(Forms.Context); 

     SetNativeControl(nativeControl); 
    } 
} 
+0

nie ufa emulatory, spróbuj uruchomić go na wielu urządzeniach, aby sądzić. –

+0

Jest to problem z renderowaniem podpikselowych. Musisz uwzględnić gęstość ekranu dla szerokości obrysu. – Cheesebaron

+0

@Cheesebaron mógłbyś być bardziej konkretny? może dostarczyć pewnych zasobów – nicks

Odpowiedz

4

Jak napisano w komentarzach nie czynnikiem gęstości wyświetlacza w swoich obliczeniach. W związku z tym na niektórych urządzeniach może to być trochę za złe, gdy renderujesz linie.

Wiem, że Xamarin Forms Labs ma klasę Display, w której można uzyskać gęstość ekranu.Jeśli chcesz, aby to się za pośrednictwem usługi zależność można zrobić coś takiego:

public interface IDisplayInfo 
{ 
    float Density { get; } 
} 

Android:

public class DisplayInfo : IDisplayInfo 
{ 
    public float Density => Application.Context.Resources.DisplayMetrics.Density; 
} 

iOS:

public class DisplayInfo : IDisplayInfo 
{ 
    public float Density => UIScreen.MainScreen.Scale; 
} 

Zarejestruj swoją usługę zależność od każda platforma:

[assembly: Xamarin.Forms.Dependency (typeof (DisplayInfo))] 

Wtedy, kiedy trzeba go użyć:

var display = DependencyService.Get<IDisplayInfo>(); 

var density = display.Density; 

Następnie wystarczy pomnożyć swoje szerokość obrysu z density.

Jest mały przykład tutaj: https://stackoverflow.com/a/14405451/368379

+0

Twój kod zwraca gęstość równą "3". czy to oznacza, że ​​powinienem pomnożyć iloczyn maski, który jest równy 196 i użyć wartości wynikowej? to zepsuje moje rozmiary. może mówisz, że to powinna być mnożna_3? – nicks

+0

proszę, czy mógłbyś to rozwinąć? nie rozumiem, co należy zrobić. – nicks

+0

co to ma wspólnego z ruchami? w ogóle nie używam – nicks

Powiązane problemy