Comments 113
Как по мне, то, как строится UI во Flutter — это самое настоящее извращение. Придумать это мог только больной на голову человек.
Видимо, я еще более больной на голову человек, потому что считаю, что система построения UI во флаттере – это едва ли не лучшее решение на рынке: статическая типизация, автодополнения от IDE, все фишки языка + не надо отдельно изучать язык разметки, composition over inheritance. Ну и примеры для флаттера и для киви у Вас все-таки разные.
Абсолютно идентичные!
Даже если не принимать во внимание такие вещи, как размер и цвет шрифта (которые Вы не указываете в примере с киви), код на флаттере можно безболезненно сократить, например, до такого:
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
main() => runApp(MaterialApp(home: Scaffold(body: Counter())));
class Counter extends StatefulWidget {
@override
State<Counter> createState() => _CounterState();
}
class _CounterState extends State<Counter> {
int _counter = 0;
@override
Widget build(BuildContext context) => Center(
child: GestureDetector(
onTap: () => setState(() => _counter++),
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Color(0xFF4eaabe),
),
width: 80.0,
child: Center(
child: Text(
_counter.toString(),
style: TextStyle(fontSize: 30.0, color: Colors.white),
),
),
),
),
);
}
Мое мнение останется неизменным в любом случае — это невозможно читать!
Ну, и да — указал размер шрифта:
from kivy.lang import Builder
from kivymd.app import MDApp
KV = """
#:import get_color_from_hex kivy.utils.get_color_from_hex
Screen:
MDCard:
MDLabel:
value: 0
text: str(self.value)
halign: "center"
on_touch_down: self.value += 1
font_size: "30sp"
canvas.before:
Color:
rgba: get_color_from_hex("#4eaabe")
Ellipse:
pos: self.center[0] - dp(25), self.center[1] - dp(25)
size: dp(50), dp(50)
"""
class HelloWorld(MDApp):
def build(self):
return Builder.load_string(KV)
HelloWorld().run()
глянул на это дело и запахло лиспом :)
Если от скобочек начинает рябить в глазах, то это хороший показатель, что надо выносить код в отдельные виджеты/функции. Этим и хороши разметка в коде и общий принцип composition over inheritance во флаттере – вы просто применяете те же самые принципы, что и в остальном коде. Например (утрированный пример, но сам принцип такой):
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
main() => runApp(MaterialApp(home: Scaffold(body: Counter())));
class Counter extends StatefulWidget {
@override
State<Counter> createState() => _CounterState();
}
class _CounterState extends State<Counter> {
int _counter = 0;
@override
Widget build(BuildContext context) => Button(
onTap: () => setState(() => _counter++),
child: ButtonText(text: _counter.toString()),
);
}
class Button extends StatelessWidget {
const Button({Key key, this.onTap, this.child}) : super(key: key);
final VoidCallback onTap;
final Widget child;
@override
Widget build(BuildContext context) => GestureDetector(
onTap: onTap,
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Color(0xFF4eaabe),
),
width: 80.0,
child: child,
),
);
}
class ButtonText extends StatelessWidget {
const ButtonText({Key key, this.text}) : super(key: key);
final String text;
@override
Widget build(BuildContext context) => Center(
child: Text(
text,
style: TextStyle(fontSize: 30.0, color: Colors.white),
),
);
}
Button и ButtonText при этом можно вынести в отдельные файлы, и вот у вас готовы переиспользуемые компоненты. А можно их просто сделать внутренней функцией, как в моем примере ниже. Такой гибкости очень сложно добиться в подходе с отдельным языком для разметки (либо сам этот язык становится слишком сложным, и возникает вопрос – а зачем писать приложение сразу на 2 языках программирования). И много компаний идут именно в этом направлении – iOS и SwiftUI, Android и Jetpack Compose (и что-то похожее было до этого у JetBrains с Anko Layout), тот же React и JSX.
тот же React и JSX
JSX это всё-таки смесь
В целом хорошо, если было бы {} вместо () было бы вообще привычно почти как какой ни будь жсон. У меня когда то давно первое время после знакомства с питоном были проблемы с возвращением на языки с си подобными скобочками. Со временем понимаешь что это все не важно. К тому же без подсветки синтаксиса ваш пример не так хорошо смотрится как мог бы. К тому же есть и плагины для разноцветных скобочек, и для отображения древовидной структуры. Лучше скринте свое IDE.
Хотелось бы увидеть приложение и для ios так как и прошлая статья направлена на андроид… Попробуйте собрать приложение под ios на flutter и на kivy…
Да без проблем!
Скрины можно? То что это скомпилировалось это уже хорошо. Но как при этом будет выглядеть приложение на ios?
Я не занимаюсь этим по одной простой причине — у меня нет iOS. А гонять все это в эмуляторе в X-Code смысла не вижу.
Но как при этом будет выглядеть приложение на ios?
Точно так же как на Андроид, если вы юзаете KivyMD.
Также хотелось бы увидеть более живой пример, например с отображением геолокации на карте на флаттер и на киви. Вот это был бы реальный пример...
Как будет выглядеть описание «типичного» элемента списка в KivyMD?
Это, как вы выразились, не "типичный" элемент в KivyMD! Но, хорошо, я покажу...
Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Icon,
Text
]
),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text,
Text
]
),
]
),
Text,
Text,
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [ Chip, Chip, Chip ]
),
Row(
children: [
Icon,
Text
]
),
]
),
]
)
Да чего уж там, приведите полный пример этой карты. Я в свою очередь сейчас размечу данную карту...
Но не суть, я не про красоту, простоту и читаемость, в данный момент мне интересно, как на KivyMD сделать разметку с главной и поперечной осями.
Готово! Так пойдет или стили меток выдержать?
Просто покажите, как выглядит код разметки, а я буду смотреть и думать, сложно-не-сложно для меня, сравнивать, думать о том, стоит ли возвращаться к Kivy, в своё время совсем не зашёл, может появление KivyMD всё изменило.
from kivy.lang import Builder
from kivymd.app import MDApp
KV = """
<MDLabel>:
size_hint_y: None
height: self.texture_size[1]
pos_hint: {"center_y": .5}
<MDChip>:
pos_hint: {"center_y": .5}
Screen:
MDCard:
orientation: "vertical"
padding: "5dp"
spacing: "10dp"
size_hint_y: None
height: self.minimum_height
pos_hint: {"center_y": .5}
BoxLayout:
size_hint_y: None
height: self.minimum_height
spacing: "10dp"
padding: "10dp"
Image:
size_hint: None, None
size: "40dp", "40dp"
source: "data/logo/kivy-icon-128.png"
MDLabel:
text: "User 123"
font_style: "H6"
bold: True
Widget:
BoxLayout:
orientation: "vertical"
spacing: "5dp"
MDLabel:
text: "2019-12.08 20:55"
font_style: "Button"
halign: "right"
MDLabel:
text: "Development"
font_style: "H6"
halign: "right"
bold: True
MDLabel:
text: "Как перенести Linux из embedded"
font_style: "H4"
bold: True
MDLabel:
text:
"Да, если не трудно. Можно даже не всей, а например «шапки» — " \
"ширина 100%, внутри два блока прижатые к краям, левый из " \
"двух горизонтальных элементов, правый из двух вертикальных. " \
"Без стилей, просто разметка."
BoxLayout:
size_hint_y: None
height: self.minimum_height
spacing: "5dp"
MDChip:
label: "arm"
icon: ''
MDChip:
label: "linux"
icon: ''
MDChip:
label: "qume"
icon: ''
Widget:
BoxLayout:
size_hint: None, None
size: self.minimum_size
padding: "10dp"
MDIconButton:
user_font_size: "18sp"
icon: "mail"
Label:
text: "13"
color: 0, 0, 0, 1
size_hint: None, None
size: self.texture_size
pos_hint: {"center_y": .5}
"""
class Card(MDApp):
def build(self):
return Builder.load_string(KV)
Card().run()
Для pycharm есть плагин для подсветки синтаксиса kv
kv-файлы и должны лежать отдельным файлом.
В PyCharm тоже — KV4Jetbrains
Только самодостаточный: скомпилировал — запустил!
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
main() => runApp(MaterialApp(home: Scaffold(body: MyCard())));
class MyCard extends StatelessWidget {
@override
Widget build(BuildContext context) => Center(
child: Card(
child: Padding(
padding: const EdgeInsets.all(8),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
_buildHeader(),
_buildTitle(context),
_buildContent(),
_buildFooter(),
],
),
),
),
);
Widget _buildHeader() => Row(
children: <Widget>[
Icon(Icons.person, size: 48),
Expanded(child: Text('User 123')),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Text('2019-12-08 20:55'),
Text('User 123'),
],
),
],
);
Widget _buildTitle(BuildContext context) => Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Text(
'Как перенести Linux из embedded',
style: Theme.of(context).textTheme.title,
),
);
Widget _buildContent() => Padding(
padding: const EdgeInsets.only(bottom: 16),
child: Text(text),
);
Widget _buildFooter() => Row(
children: <Widget>[
Expanded(
child: Wrap(
spacing: 5,
children: <Widget>[
Chip(label: Text('arm')),
Chip(label: Text('linux')),
Chip(label: Text('qemu')),
],
),
),
Icon(Icons.comment),
Text('13'),
],
);
String get text =>
'Да, если не трудно. Можно даже не всей, а например «шапки» — '
'ширина 100%, внутри два блока прижатые к краям, левый из двух '
'горизонтальных элементов, правый из двух вертикальных. '
'Без стилей, просто разметка.';
}
Это просто вырвиглазной пи… ец!
Это очень аргументированное мнение!
2) Если смотреть по коду, то не особо то и больше получается на Flutter (Если не считать строки со скобками)
3) Давайте этот же пример, но вместо счётчика будем рандомить цвет круга и менять его с анимацией длительностью 1 секунда и кривой easeOut (Мне интересно, как обстоят дела с анимацией)
— разметку вынести в отдельные файлы. В этом случае можно уже создать плагины для IDE, которые бы подсвечивали синтаксис разметки, позволяли автокомплит и рефакторинг и т.п. Ну и в целом удобнее, в этом случае версткой и кодом могли бы заниматься разные люди.
— создать докер-образ для сборки под андроид. Тогда действительно можно будет билдить одной командой, не ставя зависимостей.
Кстати, как с поддержкой нескольких активитей/окон приложения? Редкий проект ограничивается одним окном…
Как раз kivy изучаю в данный момент, только ради приложения для себя. И тут как раз эта статья, спасибо вам.
matching_dirs = glob.glob(join(self._build_dir, 'dist', '{}*'.format(dist_name)))
AttributeError: 'function' object has no attribute 'glob'
По этой инструкции все делали?
Да, только не на виртуалке, а на настоящей убунте. Причем буквально два дня назад apk собиралась без проблем. Видимо это связано с апдейтом python-for-android.
Сейчас попробую на своей машине...
Все прекрасно собирается в виртуальной машине!
play.google.com/store/apps/details?id=org.corgi.corgi
Приятный инструмент, здорово, что продолжаете над ним работу.
А как дела обстоят с KivyMD Studio?
Вроде выглядит приятно, очень хочется пощупать
Во-первых, это не МОЙ фреймворк! Во-вторых, это не натив, глазки открой!
на этом, сравнение с флаттером можно и заканчивать
А Flutter, типа натив?! Вам бы пойти почитать, как работает движок Flutter, а не позорится глупыми фразами!
Серьезно? В нативный? И все элементы UI нативные?
С этой точки зрения — пакет с приложением Kivy также компилируется в натив, поскольку все сторонние библиотеки собираются под архитектуру мобильных процессоров. Поэтому очень раздражают люди, которые не понимают сути вопроса, но пишут, что Flutter — это натив.
Возможно даже больший натив чем та же java под андроид
На этой ноте диалог с вами окончен!
Исходный код Kivy приложений не транслируется в С++. При компиляции пакета вся ресурсоемкая часть движка Kivy компилируется в натив, так как фреймворк Kivy написан на Cython, а уже все это обернуто в вызовы и API из чистого Python.
Аналогично и в примерах на Flutter! Некоторые — просто жуткий стоп кран! В следующей статье я покажу, какой Flutter тормоз. А вам могу ответить только одно — примеры в студию!
Kivy. Сборка пакетов под Android и никакой магии