Implementowanie kontrolki View
Xamarin.Forms niestandardowe kontrolki interfejsu użytkownika powinny pochodzić z klasy View, która służy do umieszczania układów i kontrolek na ekranie. W tym artykule pokazano, jak utworzyć niestandardowy moduł renderujący dla niestandardowej Xamarin.Forms kontrolki używanej do wyświetlania podglądu strumienia wideo z aparatu urządzenia.
Każdy Xamarin.Forms widok ma towarzyszący moduł renderujący dla każdej platformy, który tworzy wystąpienie kontrolki natywnej. Gdy element View
jest renderowany przez aplikację Xamarin.Forms w systemie iOS, ViewRenderer
klasę tworzy wystąpienie, co z kolei tworzy wystąpienie kontrolki natywnej UIView
. Na platformie ViewRenderer
Android klasa tworzy wystąpienie natywnej View
kontrolki. W platforma uniwersalna systemu Windows (UWP) ViewRenderer
klasa tworzy wystąpienie kontrolki natywnejFrameworkElement
. Aby uzyskać więcej informacji na temat klasy renderera i natywnych kontrolek mapowanych Xamarin.Forms na, zobacz Renderer Base Classes and Native Controls (Klasy bazowe modułu renderowania i kontrolki natywne).
Uwaga
Niektóre kontrolki w systemie Android używają szybkich modułów renderujących, które nie korzystają z ViewRenderer
klasy. Aby uzyskać więcej informacji na temat szybkich modułów renderujących, zobacz Xamarin.Forms Fast Renderers (Szybkie programy renderowania).
Na poniższym diagramie przedstawiono relację między kontrolkami View
macierzystymi i odpowiadającymi im kontrolkami natywnymi, które je implementują:
Proces renderowania może służyć do implementowania dostosowań specyficznych dla platformy przez utworzenie niestandardowego modułu renderowania dla elementu na View
każdej platformie. Proces wykonywania tej czynności jest następujący:
- Utwórz kontrolkę niestandardową Xamarin.Forms .
- Zużyj kontrolkę niestandardową z poziomu Xamarin.Forms.
- Utwórz niestandardowy moduł renderowania dla kontrolki na każdej platformie.
Każdy element zostanie omówiony z kolei, aby zaimplementować CameraPreview
program renderujący wyświetlający podgląd strumienia wideo z aparatu urządzenia. Naciśnięcie strumienia wideo spowoduje zatrzymanie i uruchomienie go.
Tworzenie kontrolki niestandardowej
Kontrolkę niestandardową można utworzyć przez podklasę View
klasy, jak pokazano w poniższym przykładzie kodu:
public class CameraPreview : View
{
public static readonly BindableProperty CameraProperty = BindableProperty.Create (
propertyName: "Camera",
returnType: typeof(CameraOptions),
declaringType: typeof(CameraPreview),
defaultValue: CameraOptions.Rear);
public CameraOptions Camera
{
get { return (CameraOptions)GetValue (CameraProperty); }
set { SetValue (CameraProperty, value); }
}
}
Kontrolka niestandardowa CameraPreview
jest tworzona w projekcie biblioteki .NET Standard i definiuje interfejs API dla kontrolki. Kontrolka niestandardowa uwidacznia Camera
właściwość używaną do kontrolowania, czy strumień wideo powinien być wyświetlany z przedniej lub tylnej kamery na urządzeniu. Jeśli wartość nie jest określona dla Camera
właściwości podczas tworzenia kontrolki, domyślnie określa kamerę tylną.
Korzystanie z kontrolki niestandardowej
Do CameraPreview
kontrolki niestandardowej można odwoływać się w języku XAML w projekcie biblioteki .NET Standard, deklarując przestrzeń nazw dla swojej lokalizacji i używając prefiksu przestrzeni nazw w niestandardowym elemencie kontrolki. Poniższy przykład kodu przedstawia sposób CameraPreview
korzystania z kontrolki niestandardowej przez stronę XAML:
<ContentPage ...
xmlns:local="clr-namespace:CustomRenderer;assembly=CustomRenderer"
...>
<StackLayout>
<Label Text="Camera Preview:" />
<local:CameraPreview Camera="Rear"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand" />
</StackLayout>
</ContentPage>
Prefiks local
przestrzeni nazw może mieć nazwę dowolnych elementów. clr-namespace
Jednak wartości i assembly
muszą być zgodne ze szczegółami kontrolki niestandardowej. Po zadeklarowaniu przestrzeni nazw prefiks jest używany do odwołwania się do kontrolki niestandardowej.
Poniższy przykład kodu pokazuje, jak kontrolka CameraPreview
niestandardowa może być zużywana przez stronę języka C#:
public class MainPageCS : ContentPage
{
public MainPageCS ()
{
...
Content = new StackLayout
{
Children =
{
new Label { Text = "Camera Preview:" },
new CameraPreview
{
Camera = CameraOptions.Rear,
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand
}
}
};
}
}
Wystąpienie kontrolki niestandardowej CameraPreview
będzie używane do wyświetlania podglądu strumienia wideo z aparatu urządzenia. Oprócz opcjonalnego określenia wartości dla Camera
właściwości dostosowanie kontrolki zostanie przeprowadzone w niestandardowym module renderowania.
Niestandardowy moduł renderowania można teraz dodać do każdego projektu aplikacji w celu utworzenia kontrolek podglądu aparatu specyficznego dla platformy.
Tworzenie niestandardowego modułu renderowania na każdej platformie
Proces tworzenia niestandardowej klasy renderera w systemach iOS i UWP jest następujący:
- Utwórz podklasę
ViewRenderer<T1,T2>
klasy, która renderuje kontrolkę niestandardową. Pierwszym argumentem typu powinna być kontrolka niestandardowa, dla których jest moduł renderowany, w tym przypadkuCameraPreview
. Drugi argument typu powinien być natywną kontrolką, która będzie implementować kontrolkę niestandardową. - Zastąpi metodę
OnElementChanged
, która renderuje kontrolkę niestandardową i zapisuje logikę, aby ją dostosować. Ta metoda jest wywoływana po utworzeniu odpowiedniej Xamarin.Forms kontrolki. ExportRenderer
Dodaj atrybut do niestandardowej klasy renderera, aby określić, że będzie on używany do renderowania kontrolki niestandardowejXamarin.Forms. Ten atrybut służy do rejestrowania niestandardowego modułu renderowania za pomocą Xamarin.Formspolecenia .
Proces tworzenia niestandardowej klasy modułu renderowania w systemie Android jako szybkiego renderowania jest następujący:
- Utwórz podklasę kontrolki systemu Android, która renderuje kontrolkę niestandardową. Ponadto określ, że podklasa będzie implementować
IVisualElementRenderer
interfejsy iIViewRenderer
. - Zaimplementuj
IVisualElementRenderer
interfejsy iIViewRenderer
w klasie szybkiego renderowania. ExportRenderer
Dodaj atrybut do niestandardowej klasy renderera, aby określić, że będzie on używany do renderowania kontrolki niestandardowejXamarin.Forms. Ten atrybut służy do rejestrowania niestandardowego modułu renderowania za pomocą Xamarin.Formspolecenia .
Uwaga
W przypadku większości Xamarin.Forms elementów opcjonalne jest udostępnienie niestandardowego modułu renderowania w każdym projekcie platformy. Jeśli niestandardowy moduł renderowania nie jest zarejestrowany, zostanie użyty domyślny moduł renderowania dla klasy bazowej kontrolki. Jednak niestandardowe programy renderowane są wymagane w każdym projekcie platformy podczas renderowania elementu View .
Na poniższym diagramie przedstawiono obowiązki każdego projektu w przykładowej aplikacji wraz z relacjami między nimi:
Kontrolka niestandardowa CameraPreview
jest renderowana przez klasy renderer specyficzne dla platformy, które pochodzą z ViewRenderer
klasy w systemach iOS i UWP oraz z FrameLayout
klasy w systemie Android. Powoduje to renderowanie każdej CameraPreview
niestandardowej kontrolki z kontrolkami specyficznymi dla platformy, jak pokazano na poniższych zrzutach ekranu:
Klasa ViewRenderer
uwidacznia metodę OnElementChanged
, która jest wywoływana podczas tworzenia niestandardowej Xamarin.Forms kontrolki w celu renderowania odpowiedniej kontrolki natywnej. Ta metoda przyjmuje ElementChangedEventArgs
parametr zawierający OldElement
właściwości i NewElement
. Te właściwości reprezentują Xamarin.Forms element dołączony do modułu renderowania, a Xamarin.Forms element, do którego jest dołączony moduł renderujący . W przykładowej aplikacji OldElement
właściwość będzie mieć null
wartość , a NewElement
właściwość będzie zawierać odwołanie do CameraPreview
wystąpienia.
Zastąpiona wersja metody , w każdej klasie modułu OnElementChanged
renderowania specyficznego dla platformy, to miejsce do wykonania wystąpienia i dostosowania natywnej kontrolki. Metoda SetNativeControl
powinna służyć do utworzenia wystąpienia kontrolki natywnej, a ta metoda przypisze również odwołanie do kontrolki Control
do właściwości . Ponadto można uzyskać odwołanie do Xamarin.Forms renderowanej kontrolki Element
za pośrednictwem właściwości .
W niektórych okolicznościach metoda może być wywoływana OnElementChanged
wiele razy. W związku z tym, aby zapobiec wyciekom pamięci, należy zachować ostrożność podczas tworzenia wystąpienia nowej natywnej kontrolki. Podejście do użycia podczas tworzenia wystąpienia nowej natywnej kontrolki w niestandardowym programie renderującym jest pokazane w poniższym przykładzie kodu:
protected override void OnElementChanged (ElementChangedEventArgs<NativeListView> e)
{
base.OnElementChanged (e);
if (e.OldElement != null)
{
// Unsubscribe from event handlers and cleanup any resources
}
if (e.NewElement != null)
{
if (Control == null)
{
// Instantiate the native control and assign it to the Control property with
// the SetNativeControl method
}
// Configure the control and subscribe to event handlers
}
}
Nową kontrolkę natywną należy utworzyć tylko raz, gdy Control
właściwość ma wartość null
. Ponadto kontrolka powinna być tworzona, konfigurowana i subskrybowana tylko po dołączeniu niestandardowego modułu renderowania do nowego Xamarin.Forms elementu. Podobnie wszystkie programy obsługi zdarzeń, które zostały zasubskrybowane, powinny być anulowane tylko wtedy, gdy element renderujący jest dołączony do zmian. Wdrożenie tego podejścia pomoże utworzyć wydajny niestandardowy moduł renderujący, który nie cierpi na przecieki pamięci.
Ważne
Metoda powinna być wywoływana SetNativeControl
tylko wtedy, gdy e.NewElement
nie null
jest .
Każda niestandardowa klasa modułu renderowania jest ozdobiona atrybutem ExportRenderer
, który rejestruje program renderujący za pomocą Xamarin.Formspolecenia . Atrybut przyjmuje dwa parametry — nazwę Xamarin.Forms typu renderowanej kontrolki niestandardowej i nazwę typu niestandardowego modułu renderowania. Prefiks assembly
atrybutu określa, że atrybut ma zastosowanie do całego zestawu.
W poniższych sekcjach omówiono implementację poszczególnych niestandardowych klas renderer specyficznych dla platformy.
Tworzenie niestandardowego modułu renderowania w systemie iOS
Poniższy przykład kodu przedstawia niestandardowy moduł renderowania dla platformy iOS:
[assembly: ExportRenderer (typeof(CameraPreview), typeof(CameraPreviewRenderer))]
namespace CustomRenderer.iOS
{
public class CameraPreviewRenderer : ViewRenderer<CameraPreview, UICameraPreview>
{
UICameraPreview uiCameraPreview;
protected override void OnElementChanged (ElementChangedEventArgs<CameraPreview> e)
{
base.OnElementChanged (e);
if (e.OldElement != null) {
// Unsubscribe
uiCameraPreview.Tapped -= OnCameraPreviewTapped;
}
if (e.NewElement != null) {
if (Control == null) {
uiCameraPreview = new UICameraPreview (e.NewElement.Camera);
SetNativeControl (uiCameraPreview);
}
// Subscribe
uiCameraPreview.Tapped += OnCameraPreviewTapped;
}
}
void OnCameraPreviewTapped (object sender, EventArgs e)
{
if (uiCameraPreview.IsPreviewing) {
uiCameraPreview.CaptureSession.StopRunning ();
uiCameraPreview.IsPreviewing = false;
} else {
uiCameraPreview.CaptureSession.StartRunning ();
uiCameraPreview.IsPreviewing = true;
}
}
...
}
}
Pod warunkiem, że Control
właściwość to null
, SetNativeControl
metoda jest wywoływana w celu utworzenia wystąpienia nowej UICameraPreview
kontrolki i przypisania odwołania do niej do Control
właściwości. Kontrolka to niestandardowa kontrolka UICameraPreview
specyficzna dla platformy, która używa AVCapture
interfejsów API do udostępniania strumienia podglądu z aparatu. Uwidacznia Tapped
zdarzenie obsługiwane przez OnCameraPreviewTapped
metodę w celu zatrzymania i uruchomienia podglądu wideo po naciśnięciu. Zdarzenie Tapped
jest subskrybowane po dołączeniu niestandardowego modułu renderowania do nowego Xamarin.Forms elementu i anulowaniu subskrypcji tylko wtedy, gdy element renderator jest dołączony do zmian.
Tworzenie niestandardowego modułu renderowania w systemie Android
Poniższy przykład kodu przedstawia szybki moduł renderowania dla platformy Android:
[assembly: ExportRenderer(typeof(CustomRenderer.CameraPreview), typeof(CameraPreviewRenderer))]
namespace CustomRenderer.Droid
{
public class CameraPreviewRenderer : FrameLayout, IVisualElementRenderer, IViewRenderer
{
// ...
CameraPreview element;
VisualElementTracker visualElementTracker;
VisualElementRenderer visualElementRenderer;
FragmentManager fragmentManager;
CameraFragment cameraFragment;
FragmentManager FragmentManager => fragmentManager ??= Context.GetFragmentManager();
public event EventHandler<VisualElementChangedEventArgs> ElementChanged;
public event EventHandler<PropertyChangedEventArgs> ElementPropertyChanged;
CameraPreview Element
{
get => element;
set
{
if (element == value)
{
return;
}
var oldElement = element;
element = value;
OnElementChanged(new ElementChangedEventArgs<CameraPreview>(oldElement, element));
}
}
public CameraPreviewRenderer(Context context) : base(context)
{
visualElementRenderer = new VisualElementRenderer(this);
}
void OnElementChanged(ElementChangedEventArgs<CameraPreview> e)
{
CameraFragment newFragment = null;
if (e.OldElement != null)
{
e.OldElement.PropertyChanged -= OnElementPropertyChanged;
cameraFragment.Dispose();
}
if (e.NewElement != null)
{
this.EnsureId();
e.NewElement.PropertyChanged += OnElementPropertyChanged;
ElevationHelper.SetElevation(this, e.NewElement);
newFragment = new CameraFragment { Element = element };
}
FragmentManager.BeginTransaction()
.Replace(Id, cameraFragment = newFragment, "camera")
.Commit();
ElementChanged?.Invoke(this, new VisualElementChangedEventArgs(e.OldElement, e.NewElement));
}
async void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
ElementPropertyChanged?.Invoke(this, e);
switch (e.PropertyName)
{
case "Width":
await cameraFragment.RetrieveCameraDevice();
break;
}
}
// ...
}
}
W tym przykładzie OnElementChanged
metoda tworzy CameraFragment
obiekt, pod warunkiem, że niestandardowy moduł renderujący jest dołączony do nowego Xamarin.Forms elementu. Typ CameraFragment
to klasa niestandardowa, która używa interfejsu Camera2
API do udostępniania strumienia podglądu z aparatu. Obiekt CameraFragment
jest usuwany, gdy Xamarin.Forms element renderator jest dołączony do zmian.
Tworzenie niestandardowego modułu renderowania na platformie UWP
W poniższym przykładzie kodu pokazano niestandardowy moduł renderowania dla platformy UWP:
[assembly: ExportRenderer(typeof(CameraPreview), typeof(CameraPreviewRenderer))]
namespace CustomRenderer.UWP
{
public class CameraPreviewRenderer : ViewRenderer<CameraPreview, Windows.UI.Xaml.Controls.CaptureElement>
{
...
CaptureElement _captureElement;
bool _isPreviewing;
protected override void OnElementChanged(ElementChangedEventArgs<CameraPreview> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
// Unsubscribe
Tapped -= OnCameraPreviewTapped;
...
}
if (e.NewElement != null)
{
if (Control == null)
{
...
_captureElement = new CaptureElement();
_captureElement.Stretch = Stretch.UniformToFill;
SetupCamera();
SetNativeControl(_captureElement);
}
// Subscribe
Tapped += OnCameraPreviewTapped;
}
}
async void OnCameraPreviewTapped(object sender, TappedRoutedEventArgs e)
{
if (_isPreviewing)
{
await StopPreviewAsync();
}
else
{
await StartPreviewAsync();
}
}
...
}
}
Pod warunkiem, że Control
właściwość to null
, jest tworzone wystąpienie SetupCamera
nowego CaptureElement
i wywoływana jest metoda , która używa interfejsu MediaCapture
API do udostępniania strumienia podglądu z aparatu. Następnie wywoływana SetNativeControl
jest metoda w celu przypisania odwołania do CaptureElement
wystąpienia do Control
właściwości . Kontrolka CaptureElement
uwidacznia Tapped
zdarzenie obsługiwane przez OnCameraPreviewTapped
metodę w celu zatrzymania i uruchomienia podglądu wideo po jej naciśnięciu. Zdarzenie Tapped
jest subskrybowane po dołączeniu niestandardowego modułu renderowania do nowego Xamarin.Forms elementu i anulowaniu subskrypcji tylko wtedy, gdy element renderator jest dołączony do zmian.
Uwaga
Ważne jest, aby zatrzymać i usunąć obiekty, które zapewniają dostęp do aparatu w aplikacji platformy UWP. Niepowodzenie tej czynności może zakłócać działanie innych aplikacji, które próbują uzyskać dostęp do aparatu urządzenia. Aby uzyskać więcej informacji, zobacz Wyświetlanie podglądu aparatu.
Podsumowanie
W tym artykule pokazano, jak utworzyć niestandardowy moduł renderujący dla niestandardowej Xamarin.Forms kontrolki używanej do wyświetlania strumienia wideo w wersji zapoznawczej z aparatu urządzenia. Xamarin.Forms niestandardowe kontrolki interfejsu użytkownika powinny pochodzić z View
klasy , która służy do umieszczania układów i kontrolek na ekranie.