Смещение начала мозаичного изображения во Flutter
Я пытаюсь создать фон параллакса в приложении Flutter, и самый эффективный способ его создания - использовать Stack
с изображением, заполняющим экран в качестве фона, а затем мой список вверху. Изображение выложено плиткойImageRepeat
установлен на оси Y. План состоит в том, чтобы сместить исходную точку плитки синхронно сScrollController
Я использую для своего списка. Затем я могу настроить исходную точку мозаичного изображения, чтобы создать эффект параллакса. Это должно быть очень просто. Вот код для контекста:
Stack(
children: [
SizedBox.expand(
child: Image(
image: AssetImage('assets/images/tiled_background_leaf.jpg'),
repeat: ImageRepeat.repeatY,
),
),
CustomScrollView(
controller: _controller,
slivers: [ ...
Моя проблема в том, что у изображения нет offset
собственность, или origin
должность. Мне нужен совет, как это сделать проще всего. Я видел, что есть нестандартные рисовальщики, методы холста и т. Д., Но все они кажутся чрезвычайно сложными, когда в рамкахImage
виджет, или, возможно, внутри другого виджета, который дал бы мне тот же эффект параллакса.
1 ответ
Спасибо @pskink за ответ (см. Комментарии выше).
Вот код для панели инструментов, которая имеет прокручиваемый список статей и мозаичное изображение с параллаксной прокруткой в качестве фона...
class DashboardRoot extends StatefulWidget {
DashboardRoot({Key key}) : super(key: key);
@override
_DashboardRootState createState() => _DashboardRootState();
}
class _DashboardRootState extends State<DashboardRoot> {
int _currentIndex = 0;
ScrollController _controller;
double _offsetY = 0.0;
_scrollListener() {
setState(() {
_offsetY = _controller.offset;
});
}
@override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((_) {
var state = Provider.of<ArticlesState>(context, listen: false);
state.initArticleStream();
});
_controller = ScrollController();
_controller.addListener(_scrollListener);
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
bottomNavigationBar: AppBottomNavigationBar(),
body: Stack(
children: [
SizedBox.expand(
child: Image(
image: AssetImage('assets/images/tiled_background_leaf.jpg'),
repeat: ImageRepeat.repeatY,
alignment: FractionalOffset(0, (_offsetY / 1000) * -1),
),
),
CustomScrollView(
controller: _controller,
slivers: [
SliverAppBar(
elevation: 0.0,
floating: true,
expandedHeight: 120,
flexibleSpace: FlexibleSpaceBar(
title: Text(NavigationManager
.instance.menuItems[_currentIndex].title),
),
actions: <Widget>[
IconButton(
icon: Icon(Icons.settings),
onPressed: () => {
locator<NavigationService>()
.navigateTo(SettingsNavigator.routeName)
},
),
IconButton(
icon: Icon(Icons.menu),
onPressed: () => {RootScaffold.openDrawer(context)},
),
],
),
Consumer<ArticlesState>(
builder: (context, state, child) {
final List<Article> list = state.articles;
if (list == null) {
return SliverToBoxAdapter(
child: Center(
child: CircularProgressIndicator(
backgroundColor: Colors.amber, strokeWidth: 1),
),
);
} else if (list.length > 0) {
return SliverGrid(
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200.0,
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
childAspectRatio: 1.0,
),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
Article article = list[index];
return ArticleCell(
article: article,
cellTapHandler: () {
Navigator.pushNamed(
context, ArticleDetail.routeName,
arguments: new ArticleDetailArguments(
article.docId, article.heading));
});
},
childCount: list.length,
),
);
} else {
return Center(
child: Text("No Articles"),
);
}
},
),
],
),
],
));
}
}
Обратите внимание на Stack
имеет фоновое изображение внутри развернутого SizedBox
так что он заполняет пространство экрана. Слой выше - этоCustomScrollView
который имеет SliverGrid
и прочее.
Важный момент - это Image
:
child: Image(
image: AssetImage('assets/images/tiled_background_leaf.jpg'),
repeat: ImageRepeat.repeatY,
alignment: FractionalOffset(0, (_offsetY / 1000) * -1),
),
а также собственность _offsetY
который установлен ScrollController
слушатель, когда пользователи прокручивают:
double _offsetY = 0.0;
_scrollListener() {
setState(() {
_offsetY = _controller.offset;
});
}
В Image
Свойство alignment используется для установки выравнивания по верхнему краю, центру, левому краю и т. д., но оно также может быть произвольным смещением. ВFractionalOffset
значение - это диапазон 0..1
но установка большего числа выше или ниже нуля также абсолютно нормально. Поскольку изображение также выложено плиткой с использованиемImageRepeat.repeatY
исходная точка мозаичного изображения перерисовывается с использованием выравнивания, и, изменяя число, вы можете создать красивый эффект прокрутки параллакса.
Заметить, что FractionalOffset(0, (_offsetY / 1000) * -1)
имеет значение смещения, деленное на 1000 (это ваша скорость, и чем выше значение, тем медленнее параллакс фона (воспринимайте это как расстояние между двумя слоями). Умножение числа на -1 переключает между положительным и отрицательным число и изменяет направление параллакса.