4
votes

Comment savoir si une image flottante a été vue par l'utilisateur

J'ai un composant Image dans un écran déroulant. Au début, lorsque l'écran s'ouvre, l'image ne peut pas être vue mais vous devez faire défiler vers le bas pour l'afficher.

Comment pouvez-vous vous assurer que l'image est complètement vue par l'utilisateur après avoir fait défiler jusqu'à elle? Je souhaite compter l'impression d'image de l'utilisateur.

Comment y parvenir en flottement?


1 commentaires

Quelle vue utilisez-vous comme ListView ou SingleChildScrollView?


3 Réponses :


1
votes

Il n'y a pas encore moyen de connaître l'élément visible dans la listView. Suivez ce problème . Vous pouvez ajouter des éléments dans la liste et vérifier si vous avez atteint le bas de la liste à l'aide du ScrollController .

import 'package:flutter/material.dart';

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

class MainPage extends StatefulWidget {
  @override
  _MainPageState createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
  ScrollController _controller;

  @override
  void initState() {
    _controller = ScrollController();
    _controller.addListener(_scrollListener);
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        backgroundColor: Colors.white,
        body: ListView(
          controller: _controller,
          children: <Widget>[
            Text(text),
            Text(text),
            Text(text),
            Text(text),
            Text(text),
            Image.network(
                'https://sample-videos.com/img/Sample-png-image-200kb.png'),
            Text(text),
          ],
        ),
      ),
    );
  }

  _scrollListener() {
    if (_controller.offset >= _controller.position.maxScrollExtent &&
        !_controller.position.outOfRange) {
      // reached at the bottom of list
      // Increment the view by one
    }
  }

  String text =
      'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur id ornare orci. In aliquet sed leo vel suscipit. Suspendisse eget dolor arcu. Duis fermentum quam suscipit nisl interdum fermentum. Aliquam laoreet, mi eu gravida rutrum, elit ex ornare erat, in egestas leo augue ac nisl. Sed vitae commodo metus, nec vulputate dui. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Phasellus rhoncus tellus nec diam elementum laoreet. Phasellus ac sapien leo. Donec dolor ante, porta quis pellentesque quis, iaculis vitae quam. Sed bibendum tortor a vestibulum malesuada. Duis non nisl congue, fringilla nulla et, laoreet odio.';
}


1 commentaires

le problème est que j'utilise NestedScrollView avec SliverAppBar , où l'écouteur de défilement m'a dit que j'ai atteint l'écran inférieur mais c'est faux car j'ai encore plus d'éléments à faire défiler (pas encore aller au fond)



3
votes

 entrez la description de l'image ici

Cette solution détectera si votre Image a été entièrement visible sur votre écran utilisateur, et modifiera la AppBar titre si c'est le cas. En supposant que vous vouliez afficher une seule page avec du contenu et une Image :

  class ImageDisplayDetection extends StatefulWidget {
  ImageDisplayDetection({Key key,}) : super(key: key);

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

  class  _ImageDisplayDetectionState extends State<ImageDisplayDetection> {

  ScrollController _controller; // To get the current scroll offset

  var _itemSize = 400.0 ; // The height of your image

  double _listSize = 2000.0 ;

  double position = 1500.0 ; // position from the top of the list where the image begins

  var seen = false ; // to report the visibility of your image


 @override
 void initState() {
    _controller = ScrollController();
    _controller.addListener(_scrollListener); // The listener will be used to check if the image has become visible
    super.initState();
 }

 _scrollListener() {
    setState(() {
      // This 60.0 is the assumed hieght of the bottom navigation buttons so the image won't be considered visible unless it is above these buttons
      if((_controller.offset + MediaQuery.of(context).size.height) >= position + _itemSize + 60.0){
        seen = true ;
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
    backgroundColor: Colors.grey.shade200 ,
    appBar: new AppBar(title: new Text(seen ? 'Image Displayed Successfully' : 'Image not displayed'),),
    body: ListView.builder(
      controller: _controller ,
      itemCount: 1,
      itemBuilder: (context, index) {
        return Container(
              height: _listSize ,
              child: new Stack(
                children: <Widget>[
                  // You can include other childern here such as TextArea

                  Positioned(
                    top: position,
                    child: SizedBox(
                      height: _itemSize,
                      width: _itemSize,
                      child: ClipRRect(
                        borderRadius: BorderRadius.circular(5.0),
                        child: Image.asset('assets/images/2.jpg'), //Change the image widget to match your own image source and name
                      ),
                    ),
                  ),
                ],
              ),
            );
         }),
       );
     }
   }

Si vous voulez plutôt une listview avec plusieurs ListTiles , vous pouvez opter pour cela réponse qui peut détecter si un enfant dont un index arbitraire est devenu visible et est affiché à une certaine position de l'écran.


0 commentaires

6
votes

Je n'avais pas beaucoup d'informations sur votre code, c'est ainsi que je l'ai résolu. L'impression n'est comptabilisée que lorsque l'image est complètement visible à l'écran, vous pouvez la modifier à l'aide de l'expression _count = . Et j'ai utilisé un simple Container pour Image .

Jetez d'abord un œil à cette capture d'écran.

 entrez la description de l'image ici


void main() => runApp(MaterialApp(home: HomePage()),);

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  ScrollController _scrollController;
  double _heightListTile = 56, _heightContainer = 200, _oldOffset = 0, _heightBox, _initialAdd;
  int _initialCount, _count, _previousCount = 0, _itemsInList = 4;

  @override
  void initState() {
    super.initState();
    _heightBox = ((_itemsInList) * _heightListTile) + _heightContainer;
    _scrollController = ScrollController();
    _scrollController.addListener(() {
      double offset = _scrollController.offset;
      if (offset >= _oldOffset) {
        _oldOffset = offset;
        _count = _initialCount + (offset + _initialAdd) ~/ _heightBox;
        if (_count != _previousCount) setState(() {});
        _previousCount = _count;
      }
    });

    Timer.run(() {
      bool isIos = Theme.of(context).platform == TargetPlatform.iOS;
      var screenHeight = MediaQuery.of(context).size.height - (isIos ? 100 : 80); // for non notches phone use 76 instead of 100 (it's the height of status and navigation bar)
      _initialCount = screenHeight ~/ _heightBox;
      _initialAdd = screenHeight % _heightBox;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(_count == null ? "Let's count" : "Images shown = ${_count}")),
      body: ListView.builder(
        itemCount: 100,
        controller: _scrollController,
        itemBuilder: (context, index) {
          if (index == 0) return Container();

          if (index != 0 && index % (_itemsInList + 1) == 0) {
            return Container(
              height: _heightContainer,
              alignment: Alignment.center,
              color: Colors.blue[(index * 20) % 1000],
              child: Text("Image #${(index + 1) ~/ 5}"),
            );
          }

          return SizedBox(height: _heightListTile, child: ListTile(title: Text("Item ${index}")));
        },
      ),
    );
  }
}


0 commentaires