Repository: flutter
Issue: VoiceOver not reading next carousel item after scroll gesture
Labels: platform-ios,framework,engine,a: accessibility,has reproducible steps,P3,team-ios,triaged-ios,found in release: 3.16

Internal: b/142594347

My app has a carousel widget which requires users to use the screenreader scroll gesture to see the next item in the carousel. A11y testers filed b/142130922.

On Android, this works fine. You perform the scroll gesture (swipe right then left), and it scrolls, then focuses on the new item and reads it.

However, on iOS, it doesn't work as well. You perform the scroll gesture (three finger swipe), and it scrolls and plays the scrolling sound. It focuses on the new item, but doesn't read it.

To reproduce:
```
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: CarouselFocusIssueRepro(),
    );
  }
}

class CarouselFocusIssueRepro extends StatefulWidget {
  final int itemCount = 10;

  /// A builder that builds widgets to appear in the carousel.
  ///
  /// Uses indices between 0 and [itemCount] exclusive.
  final IndexedWidgetBuilder itemBuilder =
      (BuildContext context, int index) => Container(
            child: Center(child: Text('item $index')),
            color: Colors.grey,
          );

  final int initialPage = 0;
  final double aspectRatio = 4 / 3;
  final double viewportFraction = 0.9;
  final EdgeInsets carouselPadding = EdgeInsets.all(10);
  final double itemSpacing = 10;

  CarouselFocusIssueRepro({Key key}) : super(key: key);

  @override
  _CarouselFocusIssueReproState createState() =>
      _CarouselFocusIssueReproState();
}

class _CarouselFocusIssueReproState extends State<CarouselFocusIssueRepro> {
  PageController _pageController;

  @override
  void initState() {
    super.initState();
    _pageController = PageController(viewportFraction: 0.9);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('title'),
      ),
      body: Center(
        child: LayoutBuilder(
          builder: _buildCarousel,
        ),
      ),
      bottomNavigationBar: Text('footer'),
    );
  }

  Widget _buildCarousel(BuildContext context, BoxConstraints constraints) {
    final itemWidth =
        (constraints.maxWidth - widget.carouselPadding.horizontal) *
            widget.viewportFraction;
    final itemHeight = itemWidth / widget.aspectRatio;
    final devicePadding = MediaQuery.of(context).padding;

    if (widget.itemCount == 0) {
      return Container(
        width: constraints.maxWidth,
        height: itemHeight,
      );
    }

    return SizedBox(
      height: itemHeight,
      child: ListView.custom(
        scrollDirection: Axis.horizontal,
        controller: _pageController,
        physics: PageScrollPhysics(),
        padding: widget.carouselPadding.copyWith(
          left: widget.carouselPadding.horizontal + devicePadding.left,
          right: widget.carouselPadding.horizontal + devicePadding.right,
        ),
        itemExtent: itemWidth +
            (widget.carouselPadding.horizontal * widget.viewportFraction),
        childrenDelegate: SliverChildBuilderDelegate(
          _buildCarouselItem,
          childCount: widget.itemCount,
        ),
      ),
    );
  }

  Widget _buildCarouselItem(BuildContext context, int index) {
    return Padding(
      padding: EdgeInsets.symmetric(horizontal: widget.itemSpacing),
      child: Semantics(
        child: widget.itemBuilder(context, index),
      ),
    );
  }
}
```