Практическое применение Sliver’ов для создания современного UI

Hola, Amigos! На связи Саша Чаплыгин, Flutter-dev агентства продуктовой разработки Amiga и соавтор телеграм-канала Flutter. Много. 

Мы уже касались темы Sliver’ов, а сегодня я предлагаю погрузиться в практику. В нашей текущей работе над приложением для сети пекарен, где множество интересных задач и вопросов интерфейса, я активно применяю Sliver’ы и другие виджеты. Давайте рассмотрим, как эти техники могут преобразить создание современного пользовательского интерфейса.

efda1420e78686f94e058deab6c7dee0.gif

Используем Stack для эффекта перекрытия карточки. Для этого применяем DraggableScrollableSheet:

Stack(
 children: [
   Padding(
     padding: const EdgeInsets.fromLTRB(16, 8, 16, 0),
     child: CreateProfileCard(state.pageState),
   ),
   DraggableScrollableSheet(
     initialChildSize: 379 / 640,
     minChildSize: 379 / 640,
     maxChildSize: 1,
     builder: (context, scrollController) {
       return Container(
         decoration: BoxDecoration(
           color: AppColors.white,
           borderRadius: const BorderRadius.vertical(top: Radius.circular(30)),
         ),
         padding: const EdgeInsets.fromLTRB(16, 6, 16, 0),
         child: Column(
           children: [
             Padding(
               padding: const EdgeInsets.only(bottom: 15.0),
               child: SvgPicture.asset(AppConstants.icons + 'holder.svg'),
             ),
             Expanded(
               child: CustomScrollView(
                 controller: scrollController,
                 slivers: [...],
               ),
             ),
           ],
         ),
       );
     },
   ),

В DraggableScrollableSheet передаем скролл контроллер в наш CustomScroollView для использования Sliver«ов:

6823c506a8be8bde7883650149964ac7.png

Для таких элементов UI используем SliverToBoxAdapter:

SliverToBoxAdapter(
 child: Padding(
   padding: const EdgeInsets.only(top: 8.0),
   child: MainBanners(state.pageState),
 ),
), // элемент CustomScrollView

class MainBanners extends StatelessWidget {
 const MainBanners(this.pageState, {Key? key}) : super(key: key);

 final MainPageState pageState;

 @override
 Widget build(BuildContext context) {
   return Container(
     height: 120,
     child: Column(
       mainAxisSize: MainAxisSize.min,
       children: [
         Expanded(
           child: CarouselSlider(
             options: CarouselOptions(
               autoPlay: true,
               height: 88,
               viewportFraction: 1.025,
             ),
             items: List.generate(
               5,
               (index) => InkWell(
                 onTap: () {},
                 child: Container(
                   width: MediaQuery.of(context).size.width,
                   margin: const EdgeInsets.symmetric(horizontal: 5),
                   decoration: BoxDecoration(
                       borderRadius: const BorderRadius.all(Radius.circular(16)), color: setColor.elementAt(index)),
                 ),
               ),
             ),
           ),
         ),
         Row(
           mainAxisAlignment: MainAxisAlignment.center,
           children: List.generate(
               5,
               (index) => InkWell(
                     onTap: () {},
                     child: Container(
                       width: 16.0,
                       height: 6.0,
                       margin: const EdgeInsets.symmetric(
                         vertical: 12.0,
                         horizontal: 4.0,
                       ),
                       decoration: BoxDecoration(
                         borderRadius: const BorderRadius.all(Radius.circular(4)),
                         color: Theme.of(context).primaryColor.withOpacity(0.5),
                       ),
                     ),
                   )).toList(),
         ),
       ],
     ),
   );
 }
}
SliverToBoxAdapter(
 child: Padding(
   padding: const EdgeInsets.only(top: 28.0, bottom: 8),
   child: Row(
     mainAxisAlignment: MainAxisAlignment.spaceBetween,
     children: [
       Text(
         'НОВИНКИ',
         style: Theme.of(context)
             .textTheme
             .headlineLarge
             ?.copyWith(color: AppColors.black),
       ),
       Row(
         children: [
           Text(
             'все',
             style: Theme.of(context)
                 .textTheme
                 .bodyLarge
                 ?.copyWith(color: AppColors.black),
           ),
           const SizedBox(width: 4),
           SvgPicture.asset(AppConstants.icons + 'deep_arrow.svg'),
         ],
       ),
     ],
   ),
 ),
),

А для прокручиваемых списков используем SliverList и SliverGrid:

SliverGrid.builder(
 gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
   crossAxisCount: 2,
   childAspectRatio: 160 / 208,
   crossAxisSpacing: 8,
   mainAxisSpacing: 8,
 ),
 itemCount: 4,
 itemBuilder: (context, index) => Container(
   padding: const EdgeInsets.only(bottom: 8),
   decoration: const BoxDecoration(
     borderRadius: BorderRadius.all(Radius.circular(8)),
     color: AppColors.white,
     boxShadow: [
       BoxShadow(
         color: Color.fromRGBO(0, 0, 0, 0.1),
         blurRadius: 6,
       ),
       BoxShadow(
         color: Color.fromRGBO(0, 0, 0, 0.15),
         blurRadius: 2,
       ),
     ],
   ),
   child: Column(
     children: [
       Container(
         height: 120,
         decoration: const BoxDecoration(
           color: Colors.red,
           borderRadius: BorderRadius.all(Radius.circular(8)),
         ),
       )
     ],
   ),
 ),
),

Slivers во Flutter представляют собой мощный инструмент для создания гибких и эффективных UI. Они позволяют легко реагировать на действия пользователя, работать с большими объемами данных и создавать привлекательные анимированные макеты.  

Смело используйте Slivers для улучшения UI/UX в ваших приложениях на Flutter, и пользователи скажут вам спасибо!

Подписывайтесь на наш авторский телеграм-канал Flutter. Много, который мы ведем командой мобильных разработчиков. Рассказываем про свой личный опыт и делимся советами от софт-скиллов до технических знаний. Будем рады новым участникам!

© Habrahabr.ru