PageView , ListView and GridView builders are designed for high number of objects. And rebuild when scrolling
Column or Row save all their children builds.
Yo can try :
SingleChildScrollView(NeverScrollable) -> Row -> A(equal screen size) and B(same)
And than animate or jump to :
For A offset 0 and for B offset screen width.
I have try, works fine

///
class AtoBExample extends StatefulWidget {
@override
_AtoBExampleState createState() => _AtoBExampleState();
}
class _AtoBExampleState extends State<AtoBExample> {
ScrollController scrollController = ScrollController();
_toB() {
// !!! Forward or any operations animations in here
// e.g animate A's opacity 1 to 0 and wait finish
scrollController.jumpTo(MediaQuery.of(context).size.width);
// And animate B's opacity 0 to 1
}
_toA() {
// !!! Forward or any operations animations in here
// e.g animate B's opacity 1 to 0 and wait finish
scrollController.jumpTo(0);
// And animate A's opacity 0 to 1
}
@override
Widget build(BuildContext context) {
var size = MediaQuery.of(context).size;
return Scaffold(
body: SingleChildScrollView(
controller: scrollController,
scrollDirection: Axis.horizontal,
physics: const NeverScrollableScrollPhysics(),
child: Row(
children: [
// A
Builder(
builder: (c) {
print('GREEN BUILD');
return InkWell(
onTap: (){
print('TO B');
_toB();
},
child: Container(
width: size.width,
height: size.height,
color: Colors.green,
),
);
},
),
Builder(
builder: (c) {
print('RED BUILD');
return InkWell(
onTap: (){
print('TO A');
_toA();
},
child: Container(
width: size.width,
height: size.height,
color: Colors.red,
),
);
},
)
],
),
),
);
}
}