Закрепите макет ниже и начните прокрутку в определенной позиции в flutter

#flutter #flutter-layout #nestedscrollview #sliverappbar

#flutter #flutter-layout #вложенный scrollview #панель слайверов

Вопрос:

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

Я мог бы показывать и скрывать кнопку добавления в пакет, используя vising visibility_detector. При медленной прокрутке он работает, но при быстрой прокрутке кнопка не видна.

Я мог бы добиться только этого

введите описание изображения здесь

Я пробовал, как показано ниже:

 Scaffold(
  body: SafeArea(
    child: CustomAppBar(
      centerTitle: false,
      expandedHeight: 355,
      searchIconShow: true,
      showBackButton: true,
      leadingWidget: const Icon(Icons.arrow_back),
      titleWidget: LayoutBuilder(
          builder: (BuildContext context, BoxConstraints constraints) {
      
        top = constraints.biggest.height;
        return top < 280
            ? FlexibleSpaceBar(
                centerTitle: false,
                titlePadding: const EdgeInsets.all(15),
                title: Container(
                  width: MediaQuery.of(context).size.width * 0.57,
                  height: 60,
                  padding: const EdgeInsets.fromLTRB(35, 0, 0, 0),
                  child: Column(
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      const Text("M.A.C Prep   Prep   Prime Fix  -Original",
                          style: TextStyle(
                              overflow: TextOverflow.ellipsis,
                              color: Colors.black,
                              fontWeight: FontWeight.normal,
                              fontSize: 14)),
                      Expanded(
                        child: Row(
                          children: const [
                            Icon(Icons.star, size: 8, color: Colors.grey),
                            SizedBox(width: 2),
                            Text(
                              "4.1",
                              style: TextStyle(
                                  color: Colors.grey, fontSize: 10),
                            ),
                            SizedBox(width: 5),
                            Icon(Icons.circle, size: 5, color: Colors.grey),
                            SizedBox(width: 5),
                            Text("Rs 1200",
                                style: TextStyle(
                                    color: Colors.grey, fontSize: 10))
                          ],
                        ),
                      )
                    ],
                  ),
                ),
                background: Container())
            : FlexibleSpaceBar(
                centerTitle: false,
                titlePadding: const EdgeInsets.all(15),
                title: SingleChildScrollView(
                  physics:const NeverScrollableScrollPhysics(),
                  child: Container(
                    height:342,
                    padding: const EdgeInsets.fromLTRB(0, 135, 0, 0),
                    child: Column(
                      mainAxisSize: MainAxisSize.max,
                      children: [
                        _buildSlider(),
                        Row(
                          children: const [
                            Expanded(
                              child: Text(
                                  "M.A.C Prep   Prep   Prime Fix  -Original",
                                  style: TextStyle(
                                      overflow: TextOverflow.ellipsis,
                                      color: Colors.black,
                                      fontWeight: FontWeight.normal,
                                      fontSize: 12)),
                            ),
                            Icon(
                              Icons.share,
                              color: Colors.black,
                              size: 20,
                            )
                          ],
                        ),
                        Row(
                          children: const [
                            Icon(Icons.star, size: 10, color: Colors.grey),
                            SizedBox(width: 2),
                            Text(
                              "4.1",
                              style:
                                  TextStyle(color: Colors.grey, fontSize: 10),
                            ),
                            SizedBox(width: 5),
                            Icon(Icons.circle, size: 5, color: Colors.grey),
                            SizedBox(width: 5),
                            Text("Rs 1200",
                                style: TextStyle(
                                    color: Colors.grey, fontSize: 10))
                          ],
                        )
                      ],
                    ),
                  ),
                ),
              );
      }),
      myWidget: Stack(children: [
        SingleChildScrollView(
          child: Column(
            children: [
              Container(height: 200, color: Colors.green),
              Container(height: 200, color: Colors.yellow),
              Container(height: 200, color: Colors.pink),
              Container(height: 200, color: Colors.grey),
              Container(height: 200, color: Colors.blueGrey),
              Container(height: 200, color: Colors.indigo),
              Container(height: 200, color: Colors.purple),
              Container(height: 200, color: Colors.green),
              Container(height: 200, color: Colors.yellow),
              Container(height: 200, color: Colors.pink),
              Container(height: 200, color: Colors.grey),
              VisibilityDetector(
                key: Key('my-widget-key'),
                onVisibilityChanged: (visibility) {
                  var visiblePercentage =
                      visibility.visibleFraction * 100;
                  if (visiblePercentage < 0) {
                    setState(() {
                      showBottomButton = false;
                    });
                  }

                  else{
                    setState(() {
                      showBottomButton = true;
                    });
                  }
                },
                child: Padding(
                  padding: const EdgeInsets.all(10.0),
                  child: Container(
                      padding: const EdgeInsets.all(20),
                      width: MediaQuery.of(context).size.width,
                      color: Colors.red,
                      child: const Text("Add to Bag",
                          style: TextStyle(color: Colors.white))),
                ),
              ),
              VisibilityDetector(
                  key: Key('my-widget-key2'),
                  onVisibilityChanged: (visibility) {

                    var visiblePercentage =
                        visibility.visibleFraction * 100;
                    if (visiblePercentage < 0) {
                      setState(() {
                        showBottomButton = true;
                      });
                    } else {
                      setState(() {
                        showBottomButton = false;
                      });
                    }
                  },
                  child: Column(
                    children: [
                      Container(height: 200, color: Colors.black),
                      Container(height: 200, color: Colors.indigo),
                      Container(height: 200, color: Colors.purple),
                      Container(height: 200, color: Colors.indigo),
                      Container(height: 200, color: Colors.purple),
                      Container(height: 200, color: Colors.indigo),
                      Container(height: 200, color: Colors.black),
                      Container(height: 200, color: Colors.purple),
                      Container(height: 200, color: Colors.black),
                      Container(height: 200, color: Colors.purple),
                      Container(height: 200, color: Colors.black),
                      Container(height: 200, color: Colors.purple),
                      Container(height: 200, color: Colors.black),
                      Container(height: 200, color: Colors.purple),
                      Container(height: 200, color: Colors.black),
                      Container(height: 200, color: Colors.purple),
                    ],
                  )),
            ],
          ),
        ),
        Visibility(
          visible: showBottomButton,
          child: Align(
            alignment: Alignment.bottomCenter,
            child: Padding(
              padding: const EdgeInsets.all(8.0),
              child: Container(
                  padding: const EdgeInsets.all(20),
                  width: MediaQuery.of(context).size.width,
                  color: Colors.red,
                  child: const Text("Add to Bag",
                      style: TextStyle(color: Colors.white))),
            ),
          ),
        ),
      ]),
    ),
  ),
);
 

И я смог добиться только этого

Ответ №1:

Вы можете сделать это с помощью CustomScrollView и Slivers простым способом:

 Scaffold(
        body: CustomScrollView(
      slivers: <Widget>[
        SliverAppBar(
          backgroundColor: Colors.red,
          expandedHeight: 200.0, // This hand the expanded height of the header
          flexibleSpace: FlexibleSpaceBar(
              background: Stack(
            alignment: AlignmentDirectional.center,
            children: [
              getMyContent(), // your content to show on header here              
            ],
          )),
        ),
        // The items that you show down
        SliverFixedExtentList(
          itemExtent: 150.0,
          delegate: SliverChildBuilderDelegate(
              (context, index) => getMyList(item: list[index]),
              childCount: list.length),
        ),
      ],
    ));
 

Комментарии:

1. как исправить и прокрутить контейнер, когда он достигнет некоторой позиции?

Ответ №2:

Вы можете достичь этого результата с помощью Listview и SliverAppBar. Я делюсь demo тем же, что и вы customize , в соответствии с вашим выбором.

 import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  ScrollController _controller = ScrollController();
  ScrollController _controller1 = ScrollController();

  @override
  void initState() {
    super.initState();
    _controller.addListener(listenChanges);
    _controller1.addListener(listListenChanges);
  }

  bool showTitle = false;
  bool isPrimary = false;

  void listenChanges() {
    if (_controller.offset >= 170) {
      showTitle = true;
    } else {
      showTitle = false;
    }
    if(_controller.offset == 0.0){
      isPrimary = false;
    }
    setState(() {});
  }

  void listListenChanges() {
    print(_controller1.offset == _controller1.position.maxScrollExtent);
    print(_controller1.offset == 0.0);
    print(_controller1.offset);
    print(_controller1.position.maxScrollExtent);
    if (_controller1.offset == _controller1.position.maxScrollExtent) {
      isPrimary = true;
    } else {
      isPrimary = false;
    }
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Fetch Data Example',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: Builder(builder: (context) => Scaffold(
            body: NestedScrollView(
              headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) => [SliverAppBar(
                // collapsedHeight: 70,
                pinned: true,
                title: Visibility(
                  visible: showTitle,
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(
                        "This is your fixed header ",
                        style:
                        TextStyle(fontSize: 14, fontWeight: FontWeight.bold),
                      ),
                      Text(
                        "This is your fixed header ",
                        style: TextStyle(
                            fontSize: 12,
                            fontWeight: FontWeight.bold,
                            color: Colors.grey),
                      ),
                    ],
                  ),
                ),
                backgroundColor: Colors.red,
                expandedHeight:
                170.0, // This hand the expanded height of the header
                flexibleSpace: FlexibleSpaceBar(
                    background: Stack(
                      alignment: AlignmentDirectional.center,
                      children: [
                        Card(
                          child: Text(
                            "This is your fixed header ",
                            style:
                            TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
                          ),
                        ), // your content to show on header here
                      ],
                    )),
              )],
              controller: _controller,
              body: ListView(
                physics: NeverScrollableScrollPhysics(),
                primary: false,
                shrinkWrap: true,
                children: [
                  Container(
                    color: Colors.yellow,
                    height: MediaQuery.of(context).size.height - 270,
                    child: Stack(
                      children: [
                        Positioned(
                            top: 0,
                            left: 0,
                            bottom: 40,
                            width: MediaQuery.of(context).size.width,
                            child: ListView.builder(
                                physics: isPrimary ? NeverScrollableScrollPhysics() : null,
                                controller: _controller1,
                                itemBuilder:
                                    (context, index) => Container(height: 100,child: Text("sssssss")),
                                itemCount: 15)),
                        Positioned(
                            bottom: 10,
                            left: 20,
                            height: 35,
                            right: 20,
                            child: ElevatedButton(onPressed: (){},child: Text("button"),)),
                      ],
                    ),
                  ),
                  Padding(
                    padding: const EdgeInsets.all(15.0),
                    child: Text("Text 1"),
                  ),
                  Padding(
                    padding: const EdgeInsets.all(15.0),
                    child: Text("Text 1"),
                  ),
                  Padding(
                    padding: const EdgeInsets.all(15.0),
                    child: Text("Text 1"),
                  )
                ],
              ),

            ))));
  }
}
 

Комментарии:

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

2. Пожалуйста, проверьте обновленный ответ, просто скопируйте и вставьте весь код и запустите его.

3. Вы проверили?

4. да, но это не все, что мне нужно

5. в чем проблема сейчас?

Ответ №3:

Решаемая проблема была в логике. Просто изменен if (visiblePercentage < 0) на

if (visiblePercentage <= 0)