Поскольку одной из потребностей на работе является отображение игровых результатов, а система Flutter не предоставляет готовых элементов управления подсчетом очков, а статьи о настраиваемых элементах управления подсчетом очков также можно найти в Интернете, которые всегда немного не соответствуют моим собственным потребностям, поэтому У меня есть следующее из этой статьи. Международная практика, см. выше
Опубликовано вpub
Добавить в pubspec.yaml
dependencies:
spon_rating_bar: ^0.0.1
Installing
$ flutter pub get
ключевой момент
Ключ должен иметь эффект трех точек
Отображение непроверенной звезды
Полный звездный дисплей
подзвездный дисплей
Принцип межзвездной оценки заключается в использовании невыбранных звезд в качестве фона, а в верхнем слое используются полные и нижние звезды для покрытия дисплея для достижения процентного эффекта.
Используйте каскадный макет стека для управления наложением двух стилей.
Используйте отсечение ClipRect, чтобы отобразить эффект менее чем полных звезд
Реализация
Сначала мы реализуем статический эффект подсчета очков.
Мы можем заранее спроектировать контент, который можно настроить, когда он будет предоставлен другим, например, количество звезд, расстояние между звездами, размер звезд и т. д. Здесь я извлек параметры компонента, которые я написал первым, вы можете настроить его в соответствии с вашими потребностями, чтобы расширить
Нечего сказать, по коду
class RatingBar extends StatefulWidget {
final int count;
final double maxRating;
final double value;
final double size;
final double padding;
final String nomalImage;
final String selectImage;
final bool selectAble;
final ValueChanged<String> onRatingUpdate;
RatingBar({
this.maxRating = 10.0,
this.count = 5,
this.value = 10.0,
this.size = 20,
this.nomalImage,
this.selectImage,
this.padding,
this.selectAble = false,
@required this.onRatingUpdate
}) : assert(nomalImage != null),
assert(selectImage != null);
@override
_RatingBarState createState() => _RatingBarState();
}
1. Фоновая звезда
Мы делаем только горизонтальный эффект, поэтому мы можем использовать Row, чтобы расположить звезды.
List<Widget> buildNomalRow() {
List<Widget> children = [];
for(int i = 0; i < widget.count; i ++) {
children.add(Image.asset(widget.nomalImage,height: widget.size,width: widget.size,));
if(i < widget.count - 1) {
children.add(SizedBox(width: widget.padding,));
}
}
return children;
}
Добавьте SizedBox в качестве прокладки между каждой звездой
2. Полные звезды и менее чем полные звезды
Мы рассчитываем соотношение баллов, соответствующее каждой звезде, в соответствии с оценкой и максимальным количеством звезд, а затем вычисляем коэффициент отсечения между количеством полных звезд и недостаточно полными звездами в соответствии с соотношением баллов.
int fullStars() {
if(value != null) {
return (value /(widget.maxRating/widget.count)).floor();
}
return 0;
}
double star() {
if(value != null) {
if(widget.count / fullStars() == widget.maxRating / value ) {
return 0;
}
return (value % (widget.maxRating/widget.count))/(widget.maxRating/widget.count);
}
return 0;
}
List<Widget> buildRow() {
int full = fullStars();
List<Widget> children = [];
for(int i = 0; i < full; i ++) {
children.add(Image.asset(widget.selectImage,height: widget.size,width: widget.size,));
if(i < widget.count - 1) {
children.add(SizedBox(width: widget.padding,),);
}
}
if(full < widget.count) {
children.add(ClipRect(
clipper: SMClipper(rating: star() * widget.size),
child: Image.asset(widget.selectImage,height: widget.size,width: widget.size),
));
}
return children;
}
Полный расчет звезд:
Соответствующее значение каждой звезды = максимальный балл / количество звезд.
Текущий рейтинг / значение количества звезд, округленное в большую сторону, представляет собой текущее количество полных звезд.
Меньше, чем полный коэффициент кадрирования звезды:
Текущая рейтинговая система делится на количество звезд, а остаток — это оценка после удаления полной звезды, а затем деление этого значения на количество звезд — это текущий коэффициент обрезки меньше полных звезд.
обрезать
Поскольку нам нужна только вертикальная обрезка, ClipRect будет достаточно.
class SMClipper extends CustomClipper<Rect>{
final double rating;
SMClipper({
this.rating
}): assert(rating != null);
@override
Rect getClip(Size size) {
return Rect.fromLTRB(0.0, 0.0, rating , size.height);
}
@override
bool shouldReclip(SMClipper oldClipper) {
return rating != oldClipper.rating;
}
}
На данный момент написан элемент управления отображением статического рейтинга. увидеть эффект
динамичный
следить за движением
Для мониторинга действий жестов мы можем использовать Listener, здесь нам нужно использовать два его метода обратного вызова onPointerMove и onPointerDown (или onPointerUp), первый используется для отслеживания скольжения, последний используется для отслеживания кликов
Listener(
child: buildRowRating(),
onPointerDown: (PointerDownEvent event){
double x = event.localPosition.dx;
if (x < 0) x = 0;
pointValue(x);
},
onPointerMove: (PointerMoveEvent event) {
double x = event.localPosition.dx;
if (x < 0) x = 0;
pointValue(x);
},
onPointerUp: (_) {
},
behavior: HitTestBehavior.deferToChild,
)
Вычислите значение оценки, представленное текущим положением пальца, в соответствии с координатой x жеста, и запустите реконструкцию после ее получения.Одной из проблем здесь является удаление интервала между звездами для обеспечения точности.
pointValue(double dx) {
if(!widget.selectAble) {
return;
}
if(dx >= widget.size * widget.count + widget.padding * (widget.count - 1)) {
value = widget.maxRating;
}else {
for(double i = 1; i < widget.count + 1;i ++) {
if(dx > widget.size * i + widget.padding *(i -1) && dx < widget.size * i + widget.padding * i) {
value = i * (widget.maxRating/widget.count);
break;
}else if(dx > widget.size * (i -1) + widget.padding*(i -1) && dx < widget.size * i+ widget.padding*i ) {
value = (dx - widget.padding *(i -1))/(widget.size * widget.count ) *widget.maxRating;
break;
}
}
}
setState(() {
widget.onRatingUpdate(value.toStringAsFixed(1));
});
}
Таким образом, пространство, которое может быть динамически забито, заполнено, как его использовать, см. Ниже.
RatingBar(
value: 9,
size: 30,
padding: 5,
nomalImage: 'img/star_nomal.png',
selectImage: 'img/star.png',
selectAble: true,
onRatingUpdate: (value) {},
maxRating: 10,
count: 6,
)
Описание каждого параметра
- value: текущее значение рейтинга
- размер: размер звезды
- заполнение: интервал между звездами
- nomalImage: пустое изображение звезды
- selectImage: изображение полной звезды
- selectAble: можно ли щелкнуть и провести пальцем, чтобы изменить значение рейтинга.
- onRatingUpdate: щелкните и проведите пальцем, чтобы изменить обратный вызов значения рейтинга, параметр представляет собой значение рейтинга типа String.
- maxRating: максимальное значение рейтинга
- count: количество звезд
прикреплятьgithubадрес