Repository: flutter
Issue: Consider changing alignmentPolicy in focus traversal
Labels: c: new feature,framework,c: proposal,f: focus,P2,team-framework,triaged-framework

### Use case

Hi. The current implementation of FocusTraversal (specifically its _moveFocus method) sets alignmentPolicy to `ScrollPositionAlignmentPolicy.keepVisibleAtEnd`, which results in a strange behavior when using Tab Traversal. See:

https://github.com/user-attachments/assets/47066d45-d077-4051-a754-7341e669c566

The problem is that the scroll view is not scrolled if the focus goes to its first element.
Reproducible example:

```dart
MaterialApp(
      home: Scaffold(
        body: Column(
          children: [
            SizedBox(
              height: 300,
              child: ListView.builder(
                cacheExtent: 100 * 10,
                itemCount: 10,
                scrollDirection: Axis.horizontal,
                itemBuilder: (context, index) => Focus(
                  onFocusChange: (hasFocus) {
                    if (hasFocus) {
                      setState(() {
                        focusedIndex = index;
                      });
                    }
                  },
                  child: AnimatedContainer(
                    duration: const Duration(milliseconds: 100),
                    margin: const EdgeInsets.all(10),
                    width: 100,
                    height: 100,
                    color: focusedIndex == index ? Colors.red : Colors.blue,
                    child: Text('Item $index'),
                  ),
                ),
              ),
            )
          ],
        ),
      ),
    )
```


### Proposal

In order to fix this, it is possible to override the requestFocusCallback in policy, like this:
```dart
MaterialApp(
      home: Scaffold(
        body: FocusScope(
          child: FocusTraversalGroup(
            policy: ReadingOrderTraversalPolicy(
              requestFocusCallback: (node, {alignment, alignmentPolicy, curve, duration}) {
                node.requestFocus();
                TraversalEdgeBehavior;
                Scrollable.ensureVisible(
                  node.context!,
                  alignment: alignment ?? 1,
                  alignmentPolicy: ScrollPositionAlignmentPolicy.explicit,
                  curve: Curves.bounceIn,
                  duration: const Duration(milliseconds: 100),
                );
              },
            ),
            child: Column(
              children: [
                SizedBox(
                  height: 300,
                  child: ListView.builder(
                    itemCount: 10,
                    scrollDirection: Axis.horizontal,
                    itemBuilder: (context, index) => Focus(
                      onFocusChange: (hasFocus) {
                        if (hasFocus) {
                          setState(() {
                            focusedIndex = index;
                          });
                        }
                      },
                      child: AnimatedContainer(
                        duration: const Duration(milliseconds: 100),
                        margin: const EdgeInsets.all(10),
                        width: 100,
                        height: 100,
                        color: focusedIndex == index ? Colors.red : Colors.blue,
                        child: Text('Item $index'),
                      ),
                    ),
                  ),
                )
              ],
            ),
          ),
        ),
      ),
    )
```

Now it looks like this:

https://github.com/user-attachments/assets/67741e7e-0ad7-4a22-8b23-2beb8e0cd91f

I think the Flutter SDK by default should deliver best experience.