Как сделать подключаемый виджет с круговой шкалой прогресса

Нечасто мне выпадает возможность создавать подключаемые виджеты в повседневной жизни, поэтому, чтобы сохранить свои навыки, мне нравится бросать себе вызов, пытаясь воссоздать виджет, который я использую регулярно. Прошло много времени с тех пор, как я делал это, поэтому на этой неделе я решил проверить свои навыки и попытаться воссоздать виджет Circular Progress Bar, который входит в модули ресурсов Native Mobile. Так что пристегнитесь и давайте отправимся в путешествие открытий в мире React и Mendix.

Прежде, чем мы начнем

Пожалуйста, уделите немного времени, прежде чем продолжить, чтобы убедиться, что у вас все настроено, прежде чем мы начнем. Тебе понадобится:

Выбор библиотеки github для использования

Знание, с чего начать такой проект, иногда может быть пугающим для разработчика, поэтому мне намного легче понять, что делать после некоторого исследования. Итак, я зашел на гитхаб и посмотрел, что уже было там. Я наткнулся на это репо из epicode-academy и решил использовать его как основу для своего компонента. В этом репо есть еще несколько проектов, поэтому, если вы ищете точную ссылку, ее здесь.

Анализируем код

Перед тем, как приступить к написанию кода, важно на самом деле просмотреть предоставленный код и убедиться, что вы понимаете, что происходит. Глядя на пример, я уже вижу, что здесь используются функциональные компоненты, и я знаю, что это потребует некоторых изменений, чтобы их можно было реализовать в подключаемом виджете, поскольку основным компонентом обычно является компонент класса.

Компоненты бывают двух типов: компоненты класса и компоненты функции. Функциональный компонент - это простая функция JavaScript, которая принимает реквизиты в качестве аргумента и возвращает элемент React. Компонент класса требует от вас расширения от React.

Создание каркаса виджета

Хватит читать, давайте код! Для начала откройте свой терминал и перейдите в каталог вашего проекта. Быстрый способ сделать это - нажать «Показать каталог приложений в проводнике» в разделе «Приложение» в верхнем меню Studio Pro. Откроется файловый менеджер с файлами вашего приложения. Скопируйте путь к файлу на панели навигации, а затем вернитесь к открытому терминалу. Введите «cd» и вставьте путь к файлу следующим образом:

cd yourFilePath

Далее нам нужно создать папку для хранения пользовательских виджетов. В вашем терминале введите:

mkdir CustomWidgets

Затем с помощью cd перейдите в только что созданную папку:

cd CustomWidgets

Теперь вы можете использовать конструктор виджетов, чтобы создать основу для виджетов. Снова в терминале используйте эту команду для вызова генератора виджетов Mendix:

@mendix/widget CircularProgressBar

Затем генератор виджетов проведет вас через создание виджета, задав несколько вопросов. Вот что я использовал:

  • Имя виджета: {Имя вашего виджета}
  • Описание виджета: {Описание вашего виджета}
  • Название организации: {название вашей организации}
  • Авторское право: {Дата вашего авторского права}
  • Лицензия: {Ваша лицензия}
  • Начальная версия: {Ваш первоначальный номер версии}
  • Автор: {Ваше имя автора}
  • Mendix Путь к проекту: ../../
  • Язык программирования: Javascript ES6.
  • Тип виджета: Собственный мобильный
  • Шаблон виджета: Пустой виджет (рекомендуется для более опытных разработчиков)
  • Модульные тесты: Нет
  • Сквозные тесты: Нет

Настройка XML виджета

Первое, что нам нужно сделать, это изменить XML виджета, чтобы мы могли получать данные от объекта контекста в форме атрибута. Для этого нам нужно создать свойство, которое может принимать целочисленное значение, также важно определить значение ключа для этого свойства. Вы можете увидеть мой XML-код виджета ниже.

<?xml version="1.0" encoding="utf-8"?>
<widget id="mendix.circularprogressbar.CircularProgressBar" needsEntityContext="true" offlineCapable="true" pluginWidget="true"
supportedPlatform="Native" xmlns="http://www.mendix.com/widget/1.0/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://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>

Главный компонент

Теперь, когда мы определили ввод данных, мы можем работать над основным компонентом. Основной компонент в этом случае предназначен только для рендеринга дочернего компонента, а также для передачи ему данных, предоставленных с помощью его свойств.

«Props» - это специальное ключевое слово в React, которое обозначает свойства и используется для передачи данных от одного компонента к другому. Но важная часть здесь заключается в том, что реквизиты данных передаются только в однонаправленном (одностороннем) потоке.

Здесь следует отметить, что, как указывалось ранее, компонент Main создается в каркасе как компонент класса. Это означает, что нам нужно немного изменить код Github.

Вот код моего основного компонента под названием 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}
/>
)
}
}

Дочерний компонент

В дочернем компоненте происходит основная часть нашей логики. Здесь мы принимаем данные из родительского компонента, снова используя props, немного логики и стилизованную библиотеку из «styled-components / native» для стилизации отдельных частей, составляющих индикатор выполнения. Наконец, мы заканчиваем оператором return, который должен отображать компонент. Проверьте код «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>
);
}

Установка зависимостей

Пришло время протестировать ваш виджет, но нам нужно позаботиться о некоторых вещах, прежде чем мы это сделаем. Мы должны убедиться, что все библиотеки, которые мы использовали, правильно импортированы в нашу папку виджетов. Снова откройте свой терминал и введите команду.

npm install --save

Подождите, пока он загрузится, и установит все зависимости, которые могут понадобиться вашему коду.

Если что-то пойдет не так или вам нужно это повторить, вы также можете выполнить чистую установку, которая удалит все модули узлов и переустановит их с помощью этой команды (но делайте это только при 100% необходимости!)

npm ci --save

Создание файла виджета .mpk.

Чтобы связать свой виджет и создать .mpk, который можно использовать в вашем проекте Mendix, выполните следующую команду в своем терминале:

npm run build

Это действие создаст код вашего виджета, а затем скопирует виджет в папку с виджетами. Последний шаг - синхронизировать каталог приложений в Studio Pro, нажав F4 или выбрав «Приложение» → «Синхронизировать каталог приложений» в верхнем меню Studio Pro.

Теперь вы можете получить доступ к своему виджету при разработке в Studio Pro. Виджет должен быть помещен в представление данных для контекста и будет ожидать, что к нему будет подключен целочисленный атрибут, но как только вы его настроите, вы можете запустить и протестировать свой новый виджет с помощью приложения Make it Native 9.

Читать далее

От издателя -

Если вам понравилась эта статья, вы можете найти больше похожих на нашей средней странице или на нашем собственном сайте блога сообщества.

Для тех, кто хочет начать работу, вы можете создать бесплатную учетную запись и получить мгновенный доступ к обучению в нашей Академии.

Заинтересованы в более активном участии нашего сообщества? Вы можете присоединиться к нам на нашем канале сообщества Slack или для тех, кто хочет принять более активное участие, присоединиться к одной из наших Встреч.