So erstellen Sie ein steckbares Widget mit kreisförmigem Fortschrittsbalken
Ich habe im Alltag nicht oft die Gelegenheit, Plug-in-Widgets zu erstellen. Um meine Fähigkeiten auf dem neuesten Stand zu halten, fordere ich mich gerne selbst heraus, indem ich versuche, ein Widget nachzubilden, das ich regelmäßig verwende. Es ist schon eine Weile her, seit ich das getan habe, also habe ich diese Woche beschlossen, meine Fähigkeiten zu testen und zu versuchen, das Circular Progress Bar-Widget nachzubilden, das in den Native Mobile-Ressourcenmodulen enthalten ist. Also schnallen Sie sich an und gehen Sie auf Entdeckungsreise in die Welt von React und Mendix.
Bevor wir beginnen
Bitte nehmen Sie sich einen Moment Zeit, bevor Sie fortfahren, um sicherzustellen, dass Sie alles eingerichtet haben, bevor wir beginnen. Sie benötigen:
- Mendix Studio Pro (in diesem Beispiel habe ich (9.1.1) verwendet.
- Node.js ist auf Ihrem Computer installiert und konfiguriert.
- Ihre IDE der Wahl, ich habe hierfür VS Code verwendet.
- Es wird empfohlen, dass Sie dies abgeschlossen haben Tutorial zu steckbaren Widgets aus der Dokumentation oder Sie haben diese Akademiekurs.
- Der Machen Sie es nativ 9 App auf Ihrem Testgerät installiert
Auswählen einer zu verwendenden GitHub-Bibliothek
Zu wissen, wo man bei einem Projekt wie diesem anfangen soll, kann für einen Entwickler manchmal entmutigend sein. Deshalb finde ich, dass es viel einfacher ist, nach etwas Recherche zu wissen, was zu tun ist. Also ging ich zu GitHub und schaute, was es bereits gab. Ich stieß auf dieses Repo von Epicode-Akademie und habe beschlossen, dies als Basis für meine Komponente zu verwenden. Es gibt noch einige andere Projekte in diesem Repo. Wenn Sie also nach dem genauen Link suchen, ist es werden auf dieser Seite erläutert.
Analysieren des Codes
Bevor Sie mit dem Coden beginnen, sollten Sie den bereitgestellten Code überprüfen und sicherstellen, dass Sie verstehen, was passiert. Wenn ich mir das Beispiel anschaue, kann ich bereits erkennen, dass hier funktionale Komponenten verwendet werden, und ich weiß, dass einige Änderungen erforderlich sind, um dies in einem steckbaren Widget zu implementieren, da die Hauptkomponente normalerweise eine Klassenkomponente ist.
Es gibt zwei Arten von Komponenten: Klassenkomponenten und Funktionskomponenten. Eine Funktionskomponente ist einfach eine einfache JavaScript-Funktion, die Eigenschaften als Argument akzeptiert und ein React-Element zurückgibt. Eine Klassenkomponente erfordert eine Erweiterung von React.
Erstellen des Widget-Gerüsts
Genug gelesen, lasst uns programmieren! Öffnen Sie zunächst Ihr Terminal und navigieren Sie zu Ihrem Projektverzeichnis. Eine schnelle Möglichkeit, dies zu tun, besteht darin, im oberen Menü von Studio Pro unter „App“ auf „App-Verzeichnis im Explorer anzeigen“ zu klicken. Dadurch wird ein Datei-Explorer mit den Dateien Ihrer App geöffnet. Kopieren Sie den Dateipfad in die Navigationsleiste und gehen Sie dann zurück zum Terminal, das Sie geöffnet haben. Geben Sie „cd“ ein und fügen Sie Ihren Dateipfad wie folgt ein:
cd yourFilePath
Als nächstes müssen wir einen Ordner erstellen, um die benutzerdefinierten Widgets zu speichern. Geben Sie in Ihrem Terminal Folgendes ein:
mkdir CustomWidgets
Wechseln Sie anschließend per CD in den soeben erstellten Ordner:
cd CustomWidgets
Jetzt können Sie den Widget-Builder verwenden, um das Widget-Gerüst für Sie zu erstellen. Verwenden Sie im Terminal erneut diesen Befehl, um den Mendix Widget-Generator:
@mendix/widget CircularProgressBar
Der Widget-Generator führt Sie dann durch die Erstellung des Widgets, indem er einige Fragen stellt. Hier sind die, die ich verwendet habe:
- Widgetname: {Ihr Widgetname}
- Widget-Beschreibung: {Ihre Widget-Beschreibung}
- Organisation Name: {Name Ihrer Organisation}
- Copyright: {Ihr Copyright-Datum}
- Lizenz: {Ihre Lizenz}
- Erste Version:{Ihre ursprüngliche Versionsnummer}
- Autor: {Ihr Autorenname}
- Mendix Projektpfad: ../../
- Programmiersprache: JavaScript ES6
- Widget-Typ: Natives Mobil
- Widget-Vorlage: Leeres Widget (empfohlen für erfahrenere Entwickler)
- Komponententests: Nein
- End-to-End-Tests: Nein
Einrichten des Widget-XML
Als Erstes müssen wir das Widget-XML ändern, damit wir Daten von der Kontextentität in Form eines Attributs empfangen können. Dazu müssen wir eine Eigenschaft erstellen, die einen ganzzahligen Wert akzeptieren kann. Außerdem ist es wichtig, den Schlüsselwert für diese Eigenschaft zu definieren. Sie können mein Widget-XML unten sehen.
<?xml version="1.0" encoding="utf-8"?>
<widget id="mendix.circularprogressbar.CircularProgressBar" needsEntityContext="true" offlineCapable="true" pluginWidget="true"
supportedPlatform="Native" xmlns="https://www.mendix.com/widget/1.0/"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://www.mendix.com/widget/1.0/ ../node_modules/mendix/custom_widget.xsd">
<name>Circular Progress Bar</name>
<description>Animated Circle Progress widget</description>
<icon>
iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAABp1BMVEUAAABV//9mzP9LtP9Ms/9Jtv9NsvdJsfpLtPpJsfdJsfhJsvhJsvdKsvdJsPhKsPhJsfdJsPhJsfdIsfhJsfdIsPdJsfhJsfhJsPhJsPhIsfhIsPdJsPdKsPdKsfdNsvdOsvdPs/dQs/dRtPdStPdTtPdUtfdWtvdXtvdauPdcuPdeufdeufhguvhiu/hju/hkvPhmvfhnvfhpvvhrv/huwPhvwfhxwfhywvhzwvh4xfl5xfl6xfl8xvl9xvl9x/mByPmCyfmFyvmGyvmJzPmKzPmLzfmNzvqPzvqQz/qT0PqU0PqU0fqX0vqY0vqa0/qe1fqg1vqj1/uk1/un2fup2vut2/uv3Puw3Puw3fuz3vu13/u23/u34Pu44Pu64fu64fy84vy94vy+4/y/4/zD5fzE5fzG5vzH5vzI5/zK6PzL6PzR6/zT7P3U7P3V7f3W7f3Y7v3Z7v3c8P3e8f3f8f3g8f3i8v3l8/3l9P3n9P3r9v7t9/7u9/7v+P7w+P7x+f7y+f70+v71+v74/P75/P76/f77/f78/f78/v79/v7+/v7////6dMsRAAAAG3RSTlMAAwURGxwhMTNic3SEh4iVp7XBzejt7vH5/f6PsMNWAAABsklEQVR4AWIYfGAUjIJRMAqYuYREJKWJAqLCPGwY+jnFpEkBEryMqPr5pEkFgkwo9kuTDviR/S9GhgFSHAgDuKXJAQIIA4TIMkAcEY4i0mQBVrgBkuQZwA43QJo8wIFhQEhEOIBQOutHJozDOP5Crp4e1RhkJ0tKGJFd6oNEdtmJyEIzpaZl5nrRZgaHM/2Pf5/vwXXfyagXgG93bwSAlEolowLMm9w83gibhXH2gKKVdD67gTnWjwCk+VVjMQS4suSnnjMLRVFc9sAHvAX2A9fySaXNBMbEZVUWscaHIMRuqwBgD8hDEbnsRmfjUKJkAQZGCTlO/xWBwIADQLIZBlY441MvfoF1xlFS/4fy+bzXKh4dgNJE7L3eh3tmtuWa+AMcMIY3dgUvZQpGEYmMw2kD7HC+R29UqyoXLaBd0QZxzgXgikLLDSqJTKU5HOcS0MsbA9jPqtwCRvXm2eorBbNIJBw3KJ9O4Yl+AAXdnyaLt7PWN3jRWLvzmAVp94zO5+n41/onfo/UpExxZqI0O7NQr0DhIq9Io7hQpbRYp7hiobRqo6ByFcNWuY6CUTAKRgEAo8X0lBD3V30AAAAASUVORK5CYII=
</icon>
<properties>
<propertyGroup caption="General">
<property key="progress" type="attribute" required="true">
<caption>Progress Indicator</caption>
<description>The attribute that contains the circularprogressbar value, should be an integer between 0 and 100</description>
<attributeTypes>
<attributeType name="Integer"/>
</attributeTypes>
</property>
</propertyGroup>
</properties>
</widget>
Die Hauptkomponente
Nachdem wir nun die Dateneingabe definiert haben, können wir an der Hauptkomponente arbeiten. Die Hauptkomponente ist in diesem Fall nur dazu gedacht, die untergeordnete Komponente zu rendern und ihr die mithilfe ihrer Eigenschaften bereitgestellten Daten zu übergeben.
„Props“ ist ein spezielles Schlüsselwort in React, das für Eigenschaften steht und zum Übergeben von Daten von einer Komponente an eine andere verwendet wird. Wichtig dabei ist jedoch, dass Dateneigenschaften nur in einem unidirektionalen (Einweg-)Fluss übergeben werden.
Hier ist zu beachten, dass, wie bereits erwähnt, die Hauptkomponente im Gerüst als Klassenkomponente erstellt wird. Das bedeutet, dass wir den Github-Code leicht ändern müssen.
Hier ist der Code für meine Hauptkomponente namens CircularProgressBar.
import { React,Component ,createElement} from "react";
import CircularProgress from "./components/CircleComponent";
export class CircularProgressBar extends Component {
constructor(props){
super(props);
this.handleChange =this.handleChange.bind(this);
const {progress} = this.props;
console.log('constuctor triggered');
}
render() {
const {progress} = this.props;
console.log('render triggered');
return (
<CircularProgress
progress={progress.value}
size={200}
/>
)
}
}
Die untergeordnete Komponente
Der Großteil unserer Logik findet in der untergeordneten Komponente statt. Hier akzeptieren wir die Daten der übergeordneten Komponente erneut mithilfe von Props, ein wenig Logik und der gestalteten Bibliothek von „styled-components/native“, um die einzelnen Teile zu gestalten, aus denen der Fortschrittsbalken besteht. Abschließend beenden wir die Komponente mit einer Return-Anweisung, die die Komponente rendern soll. Überprüfen Sie unten den Code der untergeordneten Komponente „CircleComponent“.
import React, { useRef, useEffect, createElement } from "react";
import styled from 'styled-components/native';
import {Animated} from 'react-native';
const EmptyColour = '#a0a0a1';
const ProgressColour = '#0085ff';
const CircleBase = styled(Animated.View)`
width: ${props => props.size}px;
height: ${props => props.size}px;
border-radius: ${props => props.size / 2}px;
border-width: ${props => props.size / 10}px;
`;
const EmptyCircle = styled(CircleBase)`
border-color: ${EmptyColour};
justify-content:center;
align-items: center;
transform: rotate(-45deg);
`;
const Indicator = styled(CircleBase)`
position: absolute;
border-left-color:${ProgressColour};
border-top-color:${ProgressColour};
border-bottom-color:transparent;
border-right-color:transparent;
`;
const CoverIndicator = styled(CircleBase)`
position: absolute;
border-left-color:${EmptyColour};
border-top-color:${EmptyColour};
border-bottom-color:transparent;
border-right-color:transparent;
`;
export default function CircularProgress(props) { //added input props
const {progress, size} = this.props //destructured the props
console.log (styled)
const animatedProgress = useRef(new Animated.Value(0)).current;
const animateProgress = useRef(toValue => {
Animated.spring(animatedProgress, {
toValue,
useNativeDriver: true,
}).start();
}).current;
useEffect(() => {
animateProgress(progress);
}, [animateProgress,progress]);
const firstIndicatorRotate = animatedProgress.interpolate({
inputRange: [0, 50],
outputRange: ['0deg', '180deg'],
extrapolate: 'clamp',
});
const secondIndicatorRotate = animatedProgress.interpolate({
inputRange: [0, 100],
outputRange: ['0deg', '360deg'],
extrapolate: 'clamp',
});
const secondIndictorVisibility = animatedProgress.interpolate({
inputRange: [0, 49, 50, 100],
outputRange: [0, 0, 1, 1],
extrapolate: 'clamp',
});
return (
<EmptyCircle size={size}>
<Indicator
style={{transform: [{rotate: firstIndicatorRotate}]}}
size={size}
/>
<CoverIndicator size={size} />
<Indicator
size={size}
style={{
transform: [{rotate: secondIndicatorRotate}],
opacity: secondIndictorVisibility,
}}
/>
</EmptyCircle>
);
}
Installieren von Abhängigkeiten
Es ist fast Zeit, Ihr Widget zu testen, aber vorher müssen wir noch ein paar Dinge erledigen. Wir müssen sicherstellen, dass alle von uns verwendeten Bibliotheken korrekt in unseren Widget-Ordner importiert werden. Öffnen Sie Ihr Terminal erneut und geben Sie den Befehl ein.
npm install --save
Warten Sie, bis alle Abhängigkeiten, die Ihr Code möglicherweise benötigt, heruntergeladen und installiert wurden.
Wenn etwas schief geht oder Sie dies wiederholen müssen, können Sie auch eine Neuinstallation durchführen, bei der alle Knotenmodule entfernt und mit diesem Befehl neu installiert werden (aber nur tun, wenn es wirklich nötig ist!)
npm ci --save
Erstellen einer Widget-MPK-Datei
Um Ihr Widget zu bündeln und eine .mpk-Datei zu erstellen, die Sie in Ihrem Mendix Projekt, führen Sie den folgenden Befehl in Ihrem Terminal aus:
npm run build
Diese Aktion erstellt Ihren Widget-Code und kopiert das Widget dann in Ihren Widget-Ordner. Der letzte Schritt besteht darin, Ihr App-Verzeichnis in Studio Pro zu synchronisieren, entweder durch Drücken von F4 oder durch Gehen zu „App“ → „App-Verzeichnis synchronisieren“ im oberen Menü von Studio Pro.
Jetzt können Sie beim Entwickeln in Studio Pro auf Ihr Widget zugreifen. Das Widget muss für den Kontext in eine Datenansicht eingefügt werden und erwartet, dass ein ganzzahliges Attribut damit verbunden ist. Sobald Sie dies eingerichtet haben, können Sie Ihr neues Widget mit der App „Make it Native 9“ ausführen und testen.
Lesen Sie mehr über die Erstellung eines Plug-in-Widgets
- https://docs.mendix.com/refguide/getting-the-make-it-native-app
- https://docs.mendix.com/howto/extensibility/create-a-pluggable-widget-one
- https://docs.mendix.com/howto/extensibility/create-a-pluggable-widget-two
- https://academy.mendix.com/link/path/108/Build-a-Pluggable-Widget
- https://docs.mendix.com/apidocs-mxsdk/apidocs/pluggable-widgets
- https://docs.mendix.com/apidocs-mxsdk/apidocs/client-apis-for-pluggable-widgets