IT rekvalifikácia. Seniorní programátori zarábajú až 6 000 €/mesiac a rekvalifikácia je prvým krokom. Zisti, ako na to!

3. diel - Vlastné Android komponent - Kreslený graf

V minulej lekcii, Vlastné Android komponent - Dokončenie textového poľa , sme použili vlastných parametrov pre nastavenie a dokončili vlastné vylepšené pole pre zadávanie textu pre Android.

V dnešnom Android tutoriále si ukážeme ako vytvoriť špeciálny komponent, ktorú nemáme v štandardnej ponuke a ktorú si teda budeme musieť od základu "nakresliť". Povedzme, že potrebujeme takýto graf:

Vlastné Android komponent – Graf - Vlastné View pre Android aplikácie

Pretože budeme celý View od nuly vykresľovať a nie skladať z existujúcich komponentov, odpadá nutnosť vytváranie XML návrhu tak, ako sme to robili v predchádzajúcom príklade s vlastným textovým poľom.

Parametre pre nastavenie komponenty

Nadefinujeme teda parametre, ktorými budeme môcť grafu v XML nastaviť vzhľad a nejaké tie vlastnosti. Opäť vytvoríme súbor attrs.xml a opäť ho umiestnime do res\values\attrs.xml. Jeho obsah je nasledovné:

<resources>
    <declare-styleable name="DrawView">

        <attr name="dwDirection" format="enum">
            <enum name="CW" value="1"/>
            <enum name="CCW" value="2"/>
        </attr>

        <attr name="dwStartAngle" format="integer" />
        <attr name="dwMaxValue" format="integer" />
        <attr name="dwValue" format="integer" />
        <attr name="dwDisableText" format="boolean" />
        <attr name="dwDisableAnimation" format="boolean" />
        <attr name="dwColorResGraph" format="color" />
        <attr name="dwColorResGraphBackground" format="color" />
        <attr name="dwTextColor" format="color" />
        <attr name="dwDisableQuerterLines" format="boolean" />
        <attr name="dwQuerterLinesColor" format="color" />

        <attr name="dwTextValueFormat" format="enum">
            <enum name="percentages" value="1"/>
            <enum name="value" value="2"/>
        </attr>
    </declare-styleable>
</resources>

Vysvetlíme si, k čomu jednotlivé parametre slúžia:

  • dwDirection - Smer, ktorým hodnota grafu narastá. V smere hodinových ručičiek (CW) alebo opačne (CCW). Hodnota CW je defaultný.
  • dwStartAngle - Pokiaľ nebude nastavené, nachádza sa počiatok grafu vpravo, vztiahnuté k hodinám, v mieste trojky. O veľkosť tohto parametra (veľkosť uhla v stupňoch) sa posunie počiatok grafu v smere hodinových ručičiek.
  • dwMaxValue - Maximálna hodnota, ktorú graf zobrazí a pri ktorej bude celý vyplnený. Pri nenastavený tohto parametra bude maximálna hodnota defaultne na hodnote 100.
  • dwValue - Aktuálna hodnota grafu.
  • dwDisableText - Skrytie číselné hodnoty vnútri grafu.
  • dwColorResGraph - Farba kruhového výseku grafu.
  • dwColorResGraphBackground - Farba pozadia kruhového výseku grafu.
  • dwTextColor - Farba číselné hodnoty vnútri grafu.
  • dwDisableQuerterLines - Skryť pomocné čiary označujúce štvrtiny grafu.
  • dwQuerterLinesColor - Farba pomocných čiar, označujúcich štvrtiny grafu.
  • dwTextValueFormat - Formát číselné hodnoty v strede grafu. Výber z dvoch možností - priamo zadaná hodnota alebo prepočet na percenta. Percentuálne zobrazenie je defaultný.

Tvorba triedy Dedič od View

Pokračujeme vytvorením novej triedy DrawView dedič od triedy View:

public class DrawView extends View {

    public DrawView(Context context) {
        super(context);
        init();
    }

    public DrawView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        applyAttributeSet(context, attrs);
        init();
    }

    public DrawView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        applyAttributeSet(context, attrs);
        init();
    }

    public DrawView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        applyAttributeSet(context, attrs);
        init();
    }
}

Trieda obsahuje nám už známe štyri konštruktory ai tu napíšeme metódy applyAttributeSet() a init():

// Směr pohybu výseče grafu
// CW - Ve směru hodinových ručiček
// CWW - Proti směru hodinových ručiček
public enum Direction {CW, CCW}

// Způsob zobrazení zadané hodnoty grafu
// PERCENTAGES - přepočítá na procenta
// VALUE - zobrazí přímo zadanou hodnotu
public enum ValueFormat {PERCENTAGES, VALUE}

// Proměnné k uživatelskému nastavení grafu
Direction direction = Direction.CW;
ValueFormat valueFormat = ValueFormat.PERCENTAGES;
int startAngle = 0; // Posunutí nulové hodnoty grafu
int maxValue = 100;
int value = 0;
int colorResGraph;
int colorResGraphBackground;
int colorResText;
boolean disableText;
boolean disableQuarterLines;
int colorQuarterLines;

int graphPadding = 50;       // Odsazení grafu od okrajů jeho okolního prostoru
int valueInPercentages = 0;  // Hodnota grafu přepočtená na procenta
int valueInAngle = 0;        // Hodnota grafu přepočítaná na úhel, na který je graf naplněn vůči počátku grafu
int textSize = 0;            // Proměnná pro vypočítanou velikost textu ve středu grafu


private void applyAttributeSet(Context context, AttributeSet attrs) {
    if (attrs == null) return;

    TypedArray ta = context.getTheme().obtainStyledAttributes(attrs, R.styleable.DrawView, 0, 0);

    if (ta == null) return;

    int tempDirection = ta.getInt(R.styleable.DrawView_dwDirection, 1);

    if (tempDirection == 1) {
        direction = Direction.CW;
    } else {
        direction = Direction.CCW;
    }

    int tempValueFormat = ta.getInt(R.styleable.DrawView_dwTextValueFormat, 1);

    if (tempValueFormat == 1) {
        valueFormat = ValueFormat.PERCENTAGES;
    } else {
        valueFormat = ValueFormat.VALUE;
    }

    try {
        startAngle = ta.getInt(R.styleable.DrawView_dwStartAngle, 0);
        maxValue = ta.getInt(R.styleable.DrawView_dwMaxValue, 100);
        value = valueToDraw = ta.getInt(R.styleable.DrawView_dwValue, 0);
        colorResGraph = ta.getColor(R.styleable.DrawView_dwColorResGraph, 0);
        colorResGraphBackground = ta.getColor(R.styleable.DrawView_dwColorResGraphBackground, 0);
        colorResText = ta.getColor(R.styleable.DrawView_dwTextColor, 0);
        disableText = ta.getBoolean(R.styleable.DrawView_dwDisableText, false);
        animationDisabled = ta.getBoolean(R.styleable.DrawView_dwDisableAnimation, false);
        disableQuarterLines = ta.getBoolean(R.styleable.DrawView_dwDisableQuerterLines, false);
        colorQuarterLines = ta.getColor(R.styleable.DrawView_dwQuerterLinesColor, 0);
    } finally {
        ta.recycle();
    }

    // Nastavení defaultních barev v případě, že nejsou nastaveny z venčí
    if (colorResGraph == 0) {
        colorResGraph = context.getResources().getColor(R.color.colorGraph);
    }

    if (colorResGraphBackground == 0) {
        colorResGraphBackground = context.getResources().getColor(R.color.colorGraphBackground);
    }

    if (colorResText == 0) {
        colorResText = colorResGraph;
    }

    if (colorQuarterLines == 0) {
        colorQuarterLines = colorResGraph;
    }
}

V metóde init() máme volanie metód, ktoré si napíšeme pre vykonanie niekoľkých výpočtov:

private void init() {
    computePercentages();   // Přepočet hodnoty grafu na procenta
    convertValueToAngle();  // Přepočet hodnoty na úhel, na který se graf natočí

    // Požadavek, aby došlo k novému vykreslení grafu na displeji,
    // protože byl změněn vzhled objektu. Metoda třídy View.
    invalidate();
}

private void computePercentages() {
    if (maxValue == 0) return;
    if (value == 0) valueInPercentages = 0;
    valueInPercentages = (int) (100 * valueToDraw / maxValue);
}

private void convertValueToAngle() {
    if (value < 0 || maxValue == 0) {
        valueInAngle = 0;
        return;
    }

    if (valueFormat == ValueFormat.PERCENTAGES) {
        valueInAngle = (int) (valueInPercentages * PERCENTAGES_TO_ANGLE_CONSTANT);
    } else {
        valueInAngle = (int) ((float)valueToDraw/(float)maxValue*360f);
    }
}

V metóde init() si všimnite volanie invalidate(). Ide o metódu triedy View, ktorá zaistí obnovenie View na obrazovke. Doslova podľa dokumentácie: Zruší platnosť celého View. Ak je View viditeľný, bude v budúcnosti zavolaná metóda onDraw(). Vďaka tomu objekt bude znovu vykreslený. Toto volanie je nutné vždy, kedykoľvek vykonáme nejaké zmeny majúce vplyv na vzhľad objektu.

Ďalším krokom bude prepísanie metód onMeasure() a onDraw(), čo sú metódy triedy View. Ale to až v nasledujúcej lekcii nášho seriálu, Vlastné Android komponent - Meranie a kreslenie;-)


 

Predchádzajúci článok
Vlastné Android komponent - Dokončenie textového poľa
Všetky články v sekcii
Vlastné View pre Android aplikácie
Preskočiť článok
(neodporúčame)
Vlastné Android komponent - Meranie a kreslenie
Článok pre vás napísal Pavel
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
Autor se věnuje programování v Javě, hlavně pro Android. Mezi jeho další zájmy patří Arduino, Minecraft.
Aktivity