Vytváření vlastních ovládacích prvků v Xamarin.Mac

Při práci s jazykem C# a .NET v aplikaci Xamarin.Mac máte přístup ke stejným uživatelským ovládacím prvkům, které vývojář pracuje v Objective-Caplikaci Swift a Xcode. Vzhledem k tomu, že se Xamarin.Mac integruje přímo s Xcode, můžete pomocí Tvůrce rozhraní Xcode vytvářet a udržovat uživatelské ovládací prvky (nebo je volitelně vytvářet přímo v kódu jazyka C#).

I když macOS nabízí celou řadu integrovaných uživatelských ovládacích prvků, možná budete muset vytvořit vlastní ovládací prvek, který poskytuje funkce, které nejsou předdefinované nebo odpovídají vlastnímu motivu uživatelského rozhraní (například hernímu rozhraní).

Příklad vlastního ovládacího prvku uživatelského rozhraní

V tomto článku se podíváme na základy vytváření opakovaně použitelného vlastního ovládacího prvku uživatelského rozhraní v aplikaci Xamarin.Mac. Důrazně doporučujeme, abyste si nejprve prošli článek Hello, Mac , konkrétně úvod do Xcode a Tvůrce rozhraní a výstupy a akce , protože se zabývá klíčovými koncepty a technikami, které budeme používat v tomto článku.

Možná se také budete chtít podívat na oddíly v dokumentu Interní dokumenty Xamarin.Mac pro zveřejnění tříd a metodObjective-Cjazyka C#. Vysvětluje také, které Register příkazy a Export které se používají k připojení tříd jazyka C# k Objective-C objektům a prvkům uživatelského rozhraní.

Úvod do vlastních ovládacích prvků

Jak je uvedeno výše, může docházet k tomu, že potřebujete vytvořit opakovaně použitelný vlastní ovládací prvek uživatelského rozhraní, který poskytuje jedinečné funkce uživatelského rozhraní vaší aplikace Xamarin.Mac nebo vytvořit vlastní motiv uživatelského rozhraní (například herní rozhraní).

V těchto situacích můžete snadno dědit NSControl a vytvořit vlastní nástroj, který se dá přidat do uživatelského rozhraní aplikace prostřednictvím kódu jazyka C# nebo prostřednictvím Tvůrce rozhraní Xcode. Děděním z NSControl vlastního ovládacího prvku se automaticky zobrazí všechny standardní funkce, které má integrovaný ovládací prvek uživatelského rozhraní (například NSButton).

Pokud váš vlastní ovládací prvek uživatelského rozhraní jenom zobrazuje informace (například vlastní grafování a grafický nástroj), můžete chtít dědit místo NSViewNSControl.

Bez ohledu na to, která základní třída se používá, je základní postup vytvoření vlastního ovládacího prvku stejný.

V tomto článku vytvoříte vlastní komponentu Flip Switch, která poskytuje jedinečný motiv uživatelského rozhraní a příklad vytvoření plně funkčního vlastního ovládacího prvku uživatelského rozhraní.

Sestavení vlastního ovládacího prvku

Vzhledem k tomu, že vlastní ovládací prvek, který vytváříme, bude reagovat na vstup uživatele (kliknutí levým tlačítkem myši), budeme dědit z NSControl. Tímto způsobem bude mít náš vlastní ovládací prvek automaticky všechny standardní funkce, které má integrovaný ovládací prvek uživatelského rozhraní a odpovídá jako standardní ovládací prvek macOS.

V Visual Studio pro Mac otevřete projekt Xamarin.Mac, pro který chcete vytvořit vlastní ovládací prvek uživatelského rozhraní (nebo vytvořit nový). Přidejte novou třídu a zavolejte ji NSFlipSwitch:

Přidání nové třídy

Dále upravte NSFlipSwitch.cs třídu a udělejte ji takto:

using Foundation;
using System;
using System.CodeDom.Compiler;
using AppKit;
using CoreGraphics;

namespace MacCustomControl
{
    [Register("NSFlipSwitch")]
    public class NSFlipSwitch : NSControl
    {
        #region Private Variables
        private bool _value = false;
        #endregion

        #region Computed Properties
        public bool Value {
            get { return _value; }
            set {
                // Save value and force a redraw
                _value = value;
                NeedsDisplay = true;
            }
        }
        #endregion

        #region Constructors
        public NSFlipSwitch ()
        {
            // Init
            Initialize();
        }

        public NSFlipSwitch (IntPtr handle) : base (handle)
        {
            // Init
            Initialize();
        }

        [Export ("initWithFrame:")]
        public NSFlipSwitch (CGRect frameRect) : base(frameRect) {
            // Init
            Initialize();
        }

        private void Initialize() {
            this.WantsLayer = true;
            this.LayerContentsRedrawPolicy = NSViewLayerContentsRedrawPolicy.OnSetNeedsDisplay;
        }
        #endregion

        #region Draw Methods
        public override void DrawRect (CGRect dirtyRect)
        {
            base.DrawRect (dirtyRect);

            // Use Core Graphic routines to draw our UI
            ...

        }
        #endregion

        #region Private Methods
        private void FlipSwitchState() {
            // Update state
            Value = !Value;
        }
        #endregion

    }
}

První věc, kterou si můžete všimnout vlastní třídy v tom, že dědíme a NSControl používáme příkaz Register k zveřejnění této třídy Objective-C a Xcode Interface Builderu:

[Register("NSFlipSwitch")]
public class NSFlipSwitch : NSControl

V následujících částech se podrobněji podíváme na zbytek výše uvedeného kódu.

Sledování stavu ovládacího prvku

Vzhledem k tomu, že náš vlastní ovládací prvek je přepínač, potřebujeme způsob, jak sledovat stav zapnuto/vypnuto přepínače. Zpracováváme to následujícím kódem v NSFlipSwitch:

private bool _value = false;
...

public bool Value {
    get { return _value; }
    set {
        // Save value and force a redraw
        _value = value;
        NeedsDisplay = true;
    }
}

Když se stav přepínače změní, potřebujeme způsob, jak aktualizovat uživatelské rozhraní. Děláme to vynucením ovládacího prvku překreslit jeho uživatelské rozhraní pomocí NeedsDisplay = true.

Pokud náš ovládací prvek vyžadoval více toho, že jeden stav zapnuto/vypnuto (například přepínač s více stavy se 3 pozicemi), mohli jsme k sledování stavu použít výčt . V našem příkladu se provede jednoduchá logická hodnota .

Přidali jsme také pomocnou metodu pro prohození stavu přepínače mezi zapnutým a vypnutým:

private void FlipSwitchState() {
    // Update state
    Value = !Value;
}

Později tuto pomocnou třídu rozšíříme, abychom volajícímu informovali o změně stavu přepínačů.

Kreslení rozhraní ovládacího prvku

K vykreslení uživatelského rozhraní vlastního ovládacího prvku za běhu použijeme rutiny kreslení grafického objektu Core Graphic. Než to uděláme, musíme pro kontrolu zapnout vrstvy. Provedeme to pomocí následující privátní metody:

private void Initialize() {
    this.WantsLayer = true;
    this.LayerContentsRedrawPolicy = NSViewLayerContentsRedrawPolicy.OnSetNeedsDisplay;
}

Tato metoda se volá z každého konstruktoru ovládacího prvku, aby se zajistilo, že je ovládací prvek správně nakonfigurovaný. Příklad:

public NSFlipSwitch (IntPtr handle) : base (handle)
{
    // Init
    Initialize();
}

Dále potřebujeme přepsat metodu DrawRect a přidat základní grafické rutiny pro vykreslení ovládacího prvku:

public override void DrawRect (CGRect dirtyRect)
{
    base.DrawRect (dirtyRect);

    // Use Core Graphic routines to draw our UI
    ...

}

Vizuální reprezentaci ovládacího prvku upravíme, když se změní jeho stav (například přechod z zapnuto na vypnuto). Kdykoli se stav změní, můžeme pomocí NeedsDisplay = true příkazu vynutit překreslení ovládacího prvku pro nový stav.

Reagování na vstup uživatele

Do vlastního ovládacího prvku můžeme přidat uživatelský vstup dvěma základními způsoby: Přepsat rutiny zpracování myši nebo rozpoznávání gest. Kterou metodu použijeme, bude založená na funkcích vyžadovaných naší kontrolou.

Důležité

U jakéhokoliv vlastního ovládacího prvku, který vytvoříte, byste měli použít buď metodypřepsání, neborozpoznávání gest, ale ne obojí najednou, jak můžou vzájemně kolidovat.

Zpracování uživatelského vstupu pomocí metod přepsání

Objekty, které dědí z NSControl (nebo NSView) mají několik metod přepsání pro zpracování vstupu myši nebo klávesnice. V našem příkladu chceme překlopit stav přepínače mezi zapnutým a vypnutým , když uživatel klikne na ovládací prvek pomocí levého tlačítka myši. Do třídy můžeme přidat následující metody NSFlipSwitch přepsání, které to zvládnou:

#region Mouse Handling Methods
// --------------------------------------------------------------------------------
// Handle mouse with Override Methods.
// NOTE: Use either this method or Gesture Recognizers, NOT both!
// --------------------------------------------------------------------------------
public override void MouseDown (NSEvent theEvent)
{
    base.MouseDown (theEvent);

    FlipSwitchState ();
}

public override void MouseDragged (NSEvent theEvent)
{
    base.MouseDragged (theEvent);
}

public override void MouseUp (NSEvent theEvent)
{
    base.MouseUp (theEvent);
}

public override void MouseMoved (NSEvent theEvent)
{
    base.MouseMoved (theEvent);
}
## endregion

Ve výše uvedeném kódu voláme metodu FlipSwitchState (definovanou výše), která překlopí stav zapnutí/vypnutí přepínače v MouseDown metodě. To také vynutí překreslit ovládací prvek tak, aby odrážel aktuální stav.

Zpracování uživatelského vstupu pomocí rozpoznávání gest

Volitelně můžete pomocí rozpoznávání gest zpracovat uživatele, který pracuje s ovládacím prvku. Odeberte přepsání přidaná výše, upravte metodu Initialize a udělejte ji takto:

private void Initialize() {
    this.WantsLayer = true;
    this.LayerContentsRedrawPolicy = NSViewLayerContentsRedrawPolicy.OnSetNeedsDisplay;

    // --------------------------------------------------------------------------------
    // Handle mouse with Gesture Recognizers.
    // NOTE: Use either this method or the Override Methods, NOT both!
    // --------------------------------------------------------------------------------
    var click = new NSClickGestureRecognizer (() => {
        FlipSwitchState();
    });
    AddGestureRecognizer (click);
}

Tady vytváříme novou NSClickGestureRecognizer metodu a voláme metodu FlipSwitchState , abychom změnili stav přepínače, když na něj uživatel klikne pomocí levého tlačítka myši. Metoda AddGestureRecognizer (click) přidá do ovládacího prvku rozpoznávání gest.

To, kterou metodu používáme, opět závisí na tom, čeho se snažíme dosáhnout pomocí vlastního ovládacího prvku. Pokud potřebujeme přístup nízké úrovně k interakci uživatele, použijte metody přepsání. Pokud potřebujeme předdefinované funkce, například kliknutí myší, použijte rozpoznávání gest.

Reakce na události změny stavu

Když uživatel změní stav vlastního ovládacího prvku, potřebujeme způsob, jak reagovat na změnu stavu v kódu (například udělat něco po kliknutí na vlastní tlačítko).

Pokud chcete tuto funkci poskytnout, upravte NSFlipSwitch třídu a přidejte následující kód:

#region Events
public event EventHandler ValueChanged;

internal void RaiseValueChanged() {
    if (this.ValueChanged != null)
        this.ValueChanged (this, EventArgs.Empty);

    // Perform any action bound to the control from Interface Builder
    // via an Action.
    if (this.Action !=null)
        NSApplication.SharedApplication.SendAction (this.Action, this.Target, this);
}
## endregion

Dále upravte metodu FlipSwitchState a nastavte ji jako následující:

private void FlipSwitchState() {
    // Update state
    Value = !Value;
    RaiseValueChanged ();
}

Nejprve poskytneme ValueChanged událost, do které můžeme přidat obslužnou rutinu v kódu jazyka C#, abychom mohli provést akci, když uživatel změní stav přepínače.

Za druhé, protože náš vlastní ovládací prvek dědí z NSControl, má automaticky akci , kterou lze přiřadit v Xcode Interface Builder. K volání této akce při změně stavu použijeme následující kód:

if (this.Action !=null)
    NSApplication.SharedApplication.SendAction (this.Action, this.Target, this);

Nejprve zkontrolujeme, jestli je k ovládacímu prvku přiřazená akce . Dále zavoláme akci , pokud byla definována.

Použití vlastního ovládacího prvku

Pomocí plně definovaného vlastního ovládacího prvku ho můžeme přidat do uživatelského rozhraní aplikace Xamarin.Mac pomocí kódu jazyka C# nebo v Tvůrci rozhraní Xcode.

Pokud chcete přidat ovládací prvek pomocí Tvůrce rozhraní, nejprve proveďte čisté sestavení projektu Xamarin.Mac a poklikáním otevřete Main.storyboard soubor v Tvůrci rozhraní pro úpravy:

Úprava scénáře v Xcode

V dalším kroku přetáhněte Custom View návrh uživatelského rozhraní:

Výběr vlastního zobrazení z knihovny

Pokud je vlastní zobrazení stále vybrané, přepněte na Kontrolu identit a změňte třídu zobrazení naNSFlipSwitch:

Nastavení třídy View

Přepněte do Editoru asistentů a vytvořte výstup pro vlastní ovládací prvek (ujistěte se, že ho chcete svázat v ViewController.h souboru a ne v .m souboru):

Konfigurace nové zásuvky

Uložte změny, vraťte se do Visual Studio pro Mac a povolte synchronizaci změn. ViewController.cs Upravte soubor a udělejte metodu ViewDidLoad takto:

public override void ViewDidLoad ()
{
    base.ViewDidLoad ();

    // Do any additional setup after loading the view.
    OptionTwo.ValueChanged += (sender, e) => {
        // Display the state of the option switch
        Console.WriteLine("Option Two: {0}", OptionTwo.Value);
    };
}

Zde odpovíme na ValueChanged událost, kterou jsme definovali výše ve NSFlipSwitch třídě, a zapíšeme aktuální hodnotu , když uživatel klikne na ovládací prvek.

Volitelně se můžeme vrátit do Tvůrce rozhraní a definovat akci ovládacího prvku:

Konfigurace nové akce

Znovu upravte ViewController.cs soubor a přidejte následující metodu:

partial void OptionTwoFlipped (Foundation.NSObject sender) {
    // Display the state of the option switch
    Console.WriteLine("Option Two: {0}", OptionTwo.Value);
}

Důležité

V Tvůrci rozhraní byste měli použít buď událost , nebo definovat akci , ale neměli byste současně používat obě metody, nebo by mohly být v konfliktu s ostatními.

Shrnutí

Tento článek se podrobně podíval na vytvoření opakovaně použitelného vlastního ovládacího prvku uživatelského rozhraní v aplikaci Xamarin.Mac. Viděli jsme, jak nakreslit uživatelské rozhraní vlastních ovládacích prvků, dva hlavní způsoby reakce na vstup myši a uživatele a jak vystavit nový ovládací prvek akcím v Tvůrci rozhraní Xcode.