ComSwiper(
context: context,
bannerList: .picList,
onTap: (index) {
print(index);
Navigator.of(context).push(
PageRouteBuilder(
opaque: false, // set to false
pageBuilder: (___, __, __) => CachedNetworkImage(
imageUrl: ConfigUtil.oss_url +.picList[index],
imageBuilder: (context, imageProvider) => ImageScreen(
imageProvider: imageProvider,
heroTag: _.picList[index],
mData: .picList,
index: index,
downloadFn: (index) => ImageUtil.savenNetworkImage(
context,
ConfigUtil.oss_url +.picList[index])),
placeholder: (context, url) => Container(
color: Colors.black,
child: const Center(
child: CircularProgressIndicator(
color: Colors.white))),
errorWidget: (context, url, error) => Container(),
fadeInDuration: const Duration(milliseconds: 0),
),
),
);
},
),
import 'dart:math';
import 'package:extended_image/extended_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:toptongpin/app/res/colors.dart';
import 'package:toptongpin/app/res/styles.dart';
import '../../../../utils/config_util.dart';
typedef DoubleClickAnimationListener = void Function();
class ImageScreen extends StatefulWidget {
const ImageScreen({
required this.imageProvider,
required this.heroTag,
required this.downloadFn,
this.mData,
this.index,
Key? key,
}) : super(key: key);
final ImageProvider imageProvider;
final String heroTag;
final Function downloadFn;
final List<dynamic>? mData;
final int? index;
@override
State<StatefulWidget> createState() {
return _ImageScreenState();
}
}
class _ImageScreenState extends State<ImageScreen>
with TickerProviderStateMixin {
Animation<double>? _doubleClickAnimation;
late DoubleClickAnimationListener _doubleClickAnimationListener;
late AnimationController _doubleClickAnimationController;
List<double> doubleTapScales = <double>[1.0, 2.0];
double fittedScale = 1.0;
double initialScale = 1.0;
int screenIndex=0;
late PageController _pageController;
GlobalKey<ExtendedImageSlidePageState> slidePagekey =
GlobalKey<ExtendedImageSlidePageState>();
void close() {
Navigator.of(context).pop();
}
@override
void initState() {
super.initState();
// 允许横屏
screenIndex=widget.index!;
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeLeft,
DeviceOrientation.landscapeRight,
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
_doubleClickAnimationController = AnimationController(
duration: const Duration(milliseconds: 150), vsync: this);
_pageController = PageController(initialPage: widget.index ?? 0);
}
@override
void dispose() {
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
]);
_doubleClickAnimationController.dispose();
clearGestureDetailsCache();
super.dispose();
}
@override
Widget build(BuildContext context) {
return OrientationBuilder(builder: ((context, orientation) {
return Container(
color: Colors.transparent,
constraints: BoxConstraints.expand(
height: MediaQuery.of(context).size.height,
),
child: Stack(
alignment: Alignment.center,
children: [
ExtendedImageSlidePage(
key: slidePagekey,
slidePageBackgroundHandler: (Offset offset, Size size) {
if (orientation == Orientation.landscape) {
return Colors.black;
}
double opacity = 0.0;
opacity = offset.distance /
(Offset(size.width, size.height).distance / 2.0);
return Colors.black
.withOpacity(min(1.0, max(1.0 - opacity, 0.0)));
},
slideType: SlideType.onlyImage,
child: GestureDetector(
onTap: close,
child: ExtendedImageSlidePageHandler(
child: Stack(
children: <Widget>[
Positioned(
top: 0,
left: 0,
bottom: 0,
right: 0,
child: ExtendedImageGesturePageView.builder(
onPageChanged: (index){
setState(() {
screenIndex=index;
print('${index}**********');
});
},
controller: ExtendedPageController(
initialPage: widget.index!,
pageSpacing: 0,
shouldIgnorePointerWhenScrolling: false,
),
itemCount: widget.mData?.length,
itemBuilder: (context, index) {
return ExtendedImage(
image: NetworkImage(ConfigUtil.oss_url +
widget.mData![index]),
enableSlideOutPage: true,
fit: BoxFit.contain,
initGestureConfigHandler: (state) {
return GestureConfig(
minScale: 0.8,
animationMinScale: 0.6,
maxScale: 2 * fittedScale,
animationMaxScale: 2.5 * fittedScale,
speed: 1.0,
inertialSpeed: 100.0,
initialScale: initialScale,
inPageView: true,
initialAlignment:
InitialAlignment.topCenter,
);
},
loadStateChanged:
(ExtendedImageState state) {
switch (state.extendedImageLoadState) {
case LoadState.loading:
return Container(
color: Colors.black,
child: const Center(
child:
CircularProgressIndicator(
color:
Colors.white)));
case LoadState.completed:
final screenHeight =
MediaQuery.of(context)
.size
.height;
final screenWidth =
MediaQuery.of(context).size.width;
final imgHeight = state
.extendedImageInfo
?.image
.height ??
1;
final imgWidth = state
.extendedImageInfo
?.image
.width ??
0;
final imgRatio = imgWidth / imgHeight;
final screenRatio =
screenWidth / screenHeight;
final fitWidthScale =
screenRatio / imgRatio;
if (screenRatio > imgRatio) {
// Long Image
initialScale = fitWidthScale;
fittedScale = fitWidthScale;
doubleTapScales[1] = fitWidthScale;
} else {
fittedScale = 1 /
fitWidthScale; // fittedHeight
doubleTapScales[1] =
1 / fitWidthScale;
}
break;
case LoadState.failed:
break;
}
return null;
},
onDoubleTap:
(ExtendedImageGestureState state) {
///you can use define pointerDownPosition as you can,
///default value is double tap pointer down postion.
final Offset? pointerDownPosition =
state.pointerDownPosition;
final double? begin =
state.gestureDetails!.totalScale;
double end;
//remove old
_doubleClickAnimation?.removeListener(
_doubleClickAnimationListener);
//stop pre
_doubleClickAnimationController.stop();
//reset to use
_doubleClickAnimationController.reset();
if (begin == doubleTapScales[0]) {
end = doubleTapScales[1];
} else {
end = doubleTapScales[0];
}
_doubleClickAnimationListener = () {
//print(_animation.value);
state.handleDoubleTap(
scale: _doubleClickAnimation!.value,
doubleTapPosition:
pointerDownPosition);
};
_doubleClickAnimation =
_doubleClickAnimationController.drive(
Tween<double>(
begin: begin, end: end));
_doubleClickAnimation!.addListener(
_doubleClickAnimationListener);
_doubleClickAnimationController.forward();
},
mode: ExtendedImageMode.gesture,
);
})),
],
),
heroBuilderForSlidingPage: (Widget result) {
return Hero(
tag: widget.heroTag,
child: result,
flightShuttleBuilder: (BuildContext flightContext,
Animation<double> animation,
HeroFlightDirection flightDirection,
BuildContext fromHeroContext,
BuildContext toHeroContext) {
final Hero hero =
(flightDirection == HeroFlightDirection.pop
? fromHeroContext.widget
: toHeroContext.widget) as Hero;
return hero.child;
},
);
},
)),
),
Positioned(
left: 10,
bottom: 50,
child: IconButton(
icon: Image.asset(
'images/close.png',
package: 'tim_ui_kit',
),
iconSize: 30,
onPressed: close,
)),
Positioned(
bottom: 62,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 8),
height: 20,
decoration: BoxDecoration(
color: Colors.white38,
borderRadius: BorderRadius.all(Radius.circular(8))
),
child: Center(
child: Text('${screenIndex+1}/${widget.mData?.length.toInt()}',style: TextStyle(fontSize: 14,color: Colors.white),),
),
)
),
Positioned(
right: 10,
bottom: 50,
child: IconButton(
icon: Image.asset(
'images/download.png',
package: 'tim_ui_kit',
),
iconSize: 30,
onPressed: (){
widget.downloadFn.call((screenIndex));
print('${screenIndex}+++++++++++++++');
},
),
)
]));
}));
}
}