각 페이지에 대한 동적 높이로 Flutter Carousel Slider 만들기 (Create a Flutter Carousel Slider with dynamic heigth for each page)


문제 설명

각 페이지에 대한 동적 높이로 Flutter Carousel Slider 만들기 (Create a Flutter Carousel Slider with dynamic heigth for each page)

점선 표시가 있는 회전 목마 슬라이더가 있습니다. 이 이미지와 같이

슬라이더의 각 페이지는 ListView가 자식으로 있는 카드 위젯입니다.

p>

카드가 Carousel 위젯 내부에 없으면 Listview 내부의 요소가 증가함에 따라 확장됩니다.

슬라이더의 각 페이지에 대해 이 동작을 유지하고 싶지만 슬라이더 안의 카드는 더 이상 콘텐츠에 따라 크기가 조정되지 않지만 미리 정의된 높이가 있는 것 같습니다(내가 지정하지 않은 경우에도!).

슬라이더 안의 카드 높이를 어떻게 동적으로 업데이트할 수 있습니까?

이것은 내 코드입니다:

main.dart 파일

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Slider App',
      home: MyHomePage(),
    );
  }
}

class GeneralEvent {
  final String title;
  final String desc;
  GeneralEvent(this.title, this.desc);
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

final List<GeneralEvent> userEvents = [
  GeneralEvent(
    "List Item 1",
    "Lorem ipsum dolor sit amet, consectetur adipisci elit.",
  ),
  GeneralEvent(
    "List Item 2",
    "Lorem ipsum dolor sit amet, consectetur adipisci elit.",
  ),
  GeneralEvent(
    "List Item 3",
    "Lorem ipsum dolor sit amet, consectetur adipisci elit.",
  ),
  GeneralEvent(
    "List Item 4",
    "Lorem ipsum dolor sit amet, consectetur adipisci elit.",
  ),
  GeneralEvent(
    "List Item 5",
    "Lorem ipsum dolor sit amet, consectetur adipisci elit.",
  ),
];

class _MyHomePageState extends State<MyHomePage> {
  final List<Card> cards = [
    Card(
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          Padding(
            padding: const EdgeInsets.all(16.0),
            child: Text(
              'Card 1',
              style: TextStyle(fontSize: 24),
            ),
          ),
          Container(
            height: 1,
            width: double.infinity,
            color: Color.fromRGBO(0, 0, 0, 0.12),
          ),
          ListView.builder(
            physics: NeverScrollableScrollPhysics(),
            shrinkWrap: true,
            itemBuilder: (ctx, index) {
              return ListTile(
                title: Text(
                  userEvents.sublist(0, 3)[index].title,
                ),
                subtitle: Text(userEvents.sublist(0, 3)[index].desc),
              );
            },
            itemCount: userEvents.sublist(0, 3).length,
          ),
        ],
      ),
    ),
    Card(
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          Padding(
            padding: const EdgeInsets.all(16.0),
            child: Text(
              'Card 2',
              style: TextStyle(fontSize: 24),
            ),
          ),
          Container(
            height: 1,
            width: double.infinity,
            color: Color.fromRGBO(0, 0, 0, 0.12),
          ),
          ListView.builder(
            physics: NeverScrollableScrollPhysics(),
            shrinkWrap: true,
            itemBuilder: (ctx, index) {
              return ListTile(
                title: Text(
                  userEvents.sublist(3)[index].title,
                ),
                subtitle: Text(userEvents.sublist(3)[index].desc),
              );
            },
            itemCount: userEvents.sublist(3).length,
          ),
        ],
      ),
    ),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Color.fromRGBO(235, 235, 235, 1),
      appBar: AppBar(title: Text('iWantASliderAPP')),
      body: Padding(
        padding: EdgeInsets.fromLTRB(5, 0, 5, 0),
        child: LayoutBuilder(
          builder: (context, constraints) {
            return ListView(
              children: <Widget>[
                CarouselWithIndicator(cards),
                Padding(
                  padding: const EdgeInsets.fromLTRB(0, 50, 0, 0),
                  child: Text(
                    "if the Card is not in the slider it resize properly:",
                  ),
                ),
                cards[0]
              ],
            );
          },
        ),
      ),
    );
  }
} 

carousel.dart

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

class CarouselWithIndicator extends StatefulWidget {
  final List cards;

  CarouselWithIndicator(this.cards);

  @override
  _CarouselWithIndicatorState createState() => _CarouselWithIndicatorState();
}

class _CarouselWithIndicatorState extends State<CarouselWithIndicator> {
  List<T> map<T>(List list, Function handler) {
    List<T> result = [];
    for (var i = 0; i < list.length; i++) {
      result.add(handler(i, list[i]));
    }
    return result;
  }

  int _current = 0;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        CarouselSlider(
          // height: // NO HEIGHT SPECIFIED!
          viewportFraction: 1.0,
          enlargeCenterPage: true,
          enableInfiniteScroll: false,
          onPageChanged: (index) {
            setState(() {
              _current = index;
            });
          },
          items: widget.cards.map((card) {
            return Builder(
              builder: (BuildContext context) {
                return Container(
                  width: MediaQuery.of(context).size.width,
                  child: card,
                );
              },
            );
          }).toList(),
        ),
        SizedBox(
          height: 5,
        ),
        Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: map<Widget>(widget.cards, (index, card) {
            return Container(
              width: 10.0,
              height: 10.0,
              margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 3.0),
              decoration: BoxDecoration(
                shape: BoxShape.circle,
                color: _current == index ? Colors.grey : Color.fromRGBO(200, 200, 200, 1),
              ),
            );
          }),
        ),
      ],
    );
  }
}

참조 솔루션

방법 1:

I finally found a solution to this with the help of runtime height determination. Link to runtime size determination question : How to get height of a Widget?

Just define a height variable and update it in Measure size's onChanged Function.

MeasureSizeRenderObject.dart

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

typedef void OnWidgetSizeChange(Size size);

class MeasureSizeRenderObject extends RenderProxyBox {
  Size oldSize;
  final OnWidgetSizeChange onChange;

  MeasureSizeRenderObject(this.onChange);

  @override
  void performLayout() {
    super.performLayout();

    Size newSize = child.size;
    if (oldSize == newSize) return;

    oldSize = newSize;
    WidgetsBinding.instance.addPostFrameCallback((_) {
      onChange(newSize);
    });
  }
}

class MeasureSize extends SingleChildRenderObjectWidget {
  final OnWidgetSizeChange onChange;

  const MeasureSize({
    Key key,
    @required this.onChange,
    @required Widget child,
  }) : super(key: key, child: child);

  @override
  RenderObject createRenderObject(BuildContext context) {
    return MeasureSizeRenderObject(onChange);
  }
}

Import the above dart file and you are good to go.

In my case I had a list of days and a Map<String,List> of operational hours per day. So when ever a new operational hour was added the ListView length would grow in size.

List _days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];

Map<String, List> _operationalHours = {};

I was populating operational hours from Firebase Cloud Firestore.

CarouselSlider Code :

CarouselSlider.builder(
            itemCount: days.length,
            itemBuilder: (BuildContext context, int index, int realIdx) {
              return Card(
                shape: RoundedRectangleBorder(
                    borderRadius: BorderRadius.circular(20)),
                color: Color(0xff3b3b3b),
                child: Container(
                  width: displayWidth(context),
                  padding: EdgeInsets.all(15.0),
                  child: Column(
                    children: [
                      Text(
                        days[index],
                        style: TextStyle(
                            color: Colors.white,
                            fontWeight: FontWeight.bold,
                            fontSize: 20),
                      ),
                      SizedBox(
                        height: 15,
                      ),
                      Column(
                        children: [
                           MeasureSize(
                                      onChange: (size) {
                                        height = size.height;
                                        print("log" + height.toString());
                                        setState(() {});
                                      },
                                      child: ListView.builder(
                                          shrinkWrap: true,
                                          itemCount: operationalHours[days[index]]
.length,
                                              itemBuilder: (context, i) {
                                                return getTimeSlot(
                                             operationalHours[days[index]][i]);
                                              }),
                                        )
                            ],
                          )
                        ],
                      ),
                    ),
                  );
                },
                options: new CarouselOptions(
                    autoPlay: false,
                    viewportFraction: 1.0,
                    height: 100 + height,
                    enlargeCenterPage: false,
                    enableInfiniteScroll: false,
                    onPageChanged: (index, reason) {
                      setState(() {
                        _current = index;
                      });
                    }),
              ),

If I made any typo or bug while copying my code from IDE to StackOverflow let me know. I will update the answer.

방법 2:

This is a known issue in the library. This is the answer from the creator of the lib Currently there is no way to define a dynamic height for each carousel item. But I think it can be done by creating a dynamic height container in the carousel item.

For the whole conversation have a look at the issue: https://github.com/serenader2014/flutter_carousel_slider/issues/106

방법 3:

this is an open issue of the library but you can still achieve partially by the below code.

carousel.dart</p>

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

class CarouselWithIndicator extends StatefulWidget {
  final List cards;

  CarouselWithIndicator(this.cards);

  @override
  _CarouselWithIndicatorState createState() => _CarouselWithIndicatorState();
}

class _CarouselWithIndicatorState extends State<CarouselWithIndicator> {
  List<T> map<T>(List list, Function handler) {
    List<T> result = [];
    for (var i = 0; i < list.length; i++) {
      result.add(handler(i, list[i]));
    }
    return result;
  }

  int _current = 0;

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: <Widget>[
        Wrap(
          children: <Widget>[
            CarouselSlider(
              height: double.maxFinite,
              viewportFraction: 1.0,
              enlargeCenterPage: true,
              enableInfiniteScroll: false,
              onPageChanged: (index) {
                setState(() {
                  _current = index;
                });
              },
              items: widget.cards.map((card) {
                return Builder(
                  builder: (BuildContext context) {
                    return Container(
                      width: MediaQuery.of(context).size.width,
                      child: card,
                    );
                  },
                );
              }).toList(),
            ),
          ],
        ),
        SizedBox(
          height: 5,
        ),
        Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: map<Widget>(widget.cards, (index, card) {
            return Container(
              width: 10.0,
              height: 10.0,
              margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 3.0),
              decoration: BoxDecoration(
                shape: BoxShape.circle,
                color: _current == index
                    ? Colors.grey
                    : Color.fromRGBO(200, 200, 200, 1),
              ),
            );
          }),
        ),
      ],
    );
  }
}

main.dart file

import 'package:flutter/material.dart';

import 'carousel.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Slider App',
      home: MyHomePage(),
    );
  }
}

class GeneralEvent {
  final String title;
  final String desc;
  GeneralEvent(this.title, this.desc);
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

final List<GeneralEvent> userEvents = [
  GeneralEvent(
    "List Item 1",
    "Lorem ipsum dolor sit amet, consectetur adipisci elit.",
  ),
  GeneralEvent(
    "List Item 2",
    "Lorem ipsum dolor sit amet, consectetur adipisci elit.",
  ),
  GeneralEvent(
    "List Item 3",
    "Lorem ipsum dolor sit amet, consectetur adipisci elit.",
  ),
  GeneralEvent(
    "List Item 4",
    "Lorem ipsum dolor sit amet, consectetur adipisci elit.",
  ),
  GeneralEvent(
    "List Item 5",
    "Lorem ipsum dolor sit amet, consectetur adipisci elit.",
  ),
];

class _MyHomePageState extends State<MyHomePage> {
  List<Widget> cards = [
    Wrap(
      children: <Widget>[
        Card(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              Padding(
                padding: const EdgeInsets.all(16.0),
                child: Text(
                  'Card 1',
                  style: TextStyle(fontSize: 24),
                ),
              ),
              Container(
                height: 1,
                width: double.infinity,
                color: Color.fromRGBO(0, 0, 0, 0.12),
              ),
              ListView.builder(
                physics: NeverScrollableScrollPhysics(),
                shrinkWrap: true,
                itemBuilder: (ctx, index) {
                  return ListTile(
                    title: Text(
                      userEvents.sublist(0, 3)[index].title,
                    ),
                    subtitle: Text(userEvents.sublist(0, 3)[index].desc),
                  );
                },
                itemCount: userEvents.sublist(0, 3).length,
              ),
            ],
          ),
        ),
      ],
    ),
    Wrap(
      children: <Widget>[
        Card(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              Padding(
                padding: const EdgeInsets.all(16.0),
                child: Text(
                  'Card 2',
                  style: TextStyle(fontSize: 24),
                ),
              ),
              Container(
                height: 1,
                width: double.infinity,
                color: Color.fromRGBO(0, 0, 0, 0.12),
              ),
              ListView.builder(
                physics: NeverScrollableScrollPhysics(),
                shrinkWrap: true,
                itemBuilder: (ctx, index) {
                  return ListTile(
                    title: Text(
                      userEvents.sublist(3)[index].title,
                    ),
                    subtitle: Text(userEvents.sublist(3)[index].desc),
                  );
                },
                itemCount: userEvents.sublist(3).length,
              ),
            ],
          ),
        ),
      ],
    ),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Color.fromRGBO(235, 235, 235, 1),
      appBar: AppBar(title: Text('iWantASliderAPP')),
      body: Padding(
        padding: EdgeInsets.fromLTRB(5, 0, 5, 0),
        child: LayoutBuilder(
          builder: (context, constraints) {
            return ListView(
              children: <Widget>[
                Column(
                  mainAxisSize: MainAxisSize.min,
                  children: <Widget>[
                    CarouselWithIndicator(cards),
                  ],
                ),
                Padding(
                  padding: const EdgeInsets.fromLTRB(0, 50, 0, 0),
                  child: Text(
                    "if the Card is not in the slider it resize properly:",
                  ),
                ),
                cards[0]
              ],
            );
          },
        ),
      ),
    );
  }
}

I hope this would be somewhat helpful for you. :)

방법 4:

I recognized that using CarouselSlider for different content sizes is difficult.

I used this package instead: https://pub.dev/packages/expandable_page_view

    int current = 0;

    Container(
        width: MediaQuery.of(context).size.width,
        child: ExpandablePageView.builder(
          onPageChanged: (index) {
            setState(() {
              current = index;
            });
          },
          itemCount: itemList.length,
          itemBuilder: (context, index) {

            return GalleryItemThumbnail(
              galleryItemModel: GalleryItemModel(id: itemList[index]),
              onTap: () {
                _open(context, index);
              },
            );
          },
        ),
      ),

(by ovi_bShatanik MahantyjbaratSanket Vekariyaphilipp‑robin)

참조 문서

  1. Create a Flutter Carousel Slider with dynamic heigth for each page (CC BY‑SA 2.5/3.0/4.0)

#dart #slider #Android #flutter #carousel






관련 질문

경고 대신 오류로 "@required" 주석 ("@required" annotation as error instead of warning)

Flutter ThemeData가 텍스트에서 작동하지 않습니다 (Flutter ThemeData is not working for the Text)

Aqueduct 및 Dart: Future<List<T>>(T = ManagedObject)를 JSON으로 직렬화할 수 없습니다. (Aqueduct and Dart: Future<List<T>> (T = ManagedObject) can't be serialized to JSON)

나는 세 개의 텍스트 필드가 있는데 그 중 처음 두 개 중에서 선택하고 세 번째 필드로 작업하고 싶습니다. (I have three text fields, want to choose between first two of them, & work with third one)

각 페이지에 대한 동적 높이로 Flutter Carousel Slider 만들기 (Create a Flutter Carousel Slider with dynamic heigth for each page)

SMS를 보낼 때 flutter url_launcher의 해시 기호 뒤에 메시지 본문이 사라집니다. (Message body disappear after hash symbol in flutter url_launcher when send a SMS)

미래 방법을 조롱하고 'Null'유형을 얻지 않는 방법은 플러터에서 'Future<>'유형의 하위 유형이 아닙니다. (How to mock a future method and not get type 'Null' is not a subtype of type 'Future<>' in flutter)

【NoSuchMethodError】audio_service가 initState에서 시작되지 않습니다 (【NoSuchMethodError】audio_service does not start in initState)

플러터에서 양식 변수를 얻는 방법 (How to get form variables in flutter)

다른 프로세스에서 사용 중이기 때문에 Pub에서 항목을 삭제하지 못했습니다. (Pub failed to delete entry because it was in use by another process)

RenderViewport는 RenderSliver 유형의 하위를 예상했지만 RenderErrorBox 유형의 하위를 수신했습니다. (A RenderViewport expected a child of type RenderSliver but received a child of type RenderErrorBox)

Flutter에서 이름을 확인하는 방법은 무엇입니까? (How to validate Name in flutter?)







코멘트