Расширяемый текст в контейнере

#flutter #dart

#flutter #dart

Вопрос:

У меня есть контейнер для показа отзывов пользователей. Контейнер имеет некоторые свойства, такие как изображение профиля, рейтинг и т.д. В нижней части контейнера я хочу поместить текст обзора, и если он слишком длинный, сделайте надпись «читать больше» / «читать меньше» и отрегулируйте размер контейнера. Это код, который я использую:

 Container(
     height: 500.0,
     width: double.infinity,
     child: ReviewListWidget(userProfile: userProfile),
)
 
 Some constrais...

class ReviewListWidget extends StatefulWidget {
  final UserProfile userProfile;

  const ReviewListWidget({
    @required this.userProfile,
  });

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

class _ReviewListWidgetState extends State<ReviewListWidget> {
  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return _buildView(context);
  }

  void onTapReadMore(bool _flag) {
    setState(() => _flag = !_flag);
  }

  Widget _buildView(BuildContext context) {
    final Size size = MediaQuery.of(context).size;
    String firstHalf;
    String secondHalf;
    bool _flag = true;

    return ListView.builder(
      scrollDirection: Axis.horizontal,
      physics: BouncingScrollPhysics(),
      controller: ScrollController(),
      itemCount: widget.userProfile.reviews.length,
      itemBuilder: (_, i) {
        final review = widget.userProfile.reviews[i];

        //Logic to make the body review expandable
        if (review.bodyReview.length > 150) {
          firstHalf = review.bodyReview.substring(0, 150);
          secondHalf =
              review.bodyReview.substring(150, review.bodyReview.length);
        } else {
          firstHalf = review.bodyReview;
          secondHalf = "";
        }

        return Container(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Row(...Here Goes the profile picture, etc.),
              SizedBox(height: 12),
              
              secondHalf.isEmpty
                  ? Text(firstHalf)
                  : Column(
                      children: <Widget>[
                        new Text(_flag
                            ? (firstHalf   "...")
                            : (firstHalf   secondHalf)),
                        new InkWell(
                          child: new Row(
                            mainAxisAlignment: MainAxisAlignment.end,
                            children: <Widget>[
                              new Text(
                                _flag ? "Read more" : "Read less",
                                style: new TextStyle(color: Colors.blue),
                              ),
                            ],
                          ),
                          onTap: () => onTapReadMore(_flag),
                        ),
                       ],
                      ),
                   );
      },
    );
  }
}

 

Проблема с этой реализацией заключается в том, что когда я нажимаю кнопку, значение _flag не обновляется.

Ответ №1:

Вы должны поместить _flag переменную в класс, иначе _buildView метод создаст новую переменную со true значением при каждой сборке. Итак, код должен выглядеть следующим образом:

 class _ReviewListWidgetState extends State<ReviewListWidget> {
  bool _flag = true;

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return _buildView(context);
  }

  void onTapReadMore() {
    setState(() => _flag = !_flag);
  }

  Widget _buildView(BuildContext context) {
    final Size size = MediaQuery.of(context).size;
    String firstHalf;
    String secondHalf;

    return ListView.builder(
      scrollDirection: Axis.horizontal,
      physics: BouncingScrollPhysics(),
      controller: ScrollController(),
      itemCount: widget.userProfile.reviews.length,
      itemBuilder: (_, i) {
        final review = widget.userProfile.reviews[i];

        //Logic to make the body review expandable
        if (review.bodyReview.length > 150) {
          firstHalf = review.bodyReview.substring(0, 150);
          secondHalf =
              review.bodyReview.substring(150, review.bodyReview.length);
        } else {
          firstHalf = review.bodyReview;
          secondHalf = "";
        }

        return Container(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Row(...Here Goes the profile picture, etc.),
              SizedBox(height: 12),
              
              secondHalf.isEmpty
                  ? Text(firstHalf)
                  : Column(
                      children: <Widget>[
                        new Text(_flag
                            ? (firstHalf   "...")
                            : (firstHalf   secondHalf)),
                        new InkWell(
                          child: new Row(
                            mainAxisAlignment: MainAxisAlignment.end,
                            children: <Widget>[
                              new Text(
                                _flag ? "Read more" : "Read less",
                                style: new TextStyle(color: Colors.blue),
                              ),
                            ],
                          ),
                          onTap: () => onTapReadMore(),
                        ),
                       ],
                      ),
                   );
      },
    );
  }
}
 

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

1. Помещение _flag туда, где вы сказали, не устраняет проблему. Происходит то же самое, каждый раз, когда я нажимаю кнопку, переменная инициализируется как true : (

2. @Jsancs вам также необходимо удалить определение переменной из buildView, как я это сделал

3. О, это правда, теперь это работает 🙂 Есть идея сделать высоту контейнера такой же высокой, как и текст? Большое вам спасибо

4. @jsancs на самом деле нет. Я думаю, вам нужно покопаться в MediaQuery.