Flutter & OpenHarmony OA系统图片预览组件开发指南

前言

图片预览是OA系统中查看文档附件、聊天图片、公告配图等场景的常用功能。一个优秀的图片预览组件需要支持缩放、平移、多图切换、保存等功能。本文将详细介绍如何使用Flutter和OpenHarmony开发一个功能完善的图片预览组件,提升用户的图片查看体验。

组件功能设计

图片预览组件的核心是手势交互,需要支持双指缩放、单指平移、双击放大等操作。组件需要支持多图预览,通过左右滑动切换图片。底部显示图片索引指示器,顶部显示操作按钮如保存、分享等。背景使用黑色或半透明遮罩,突出图片内容。

Flutter端实现

图片预览组件的基础结构:

dart 复制代码
class ImagePreview extends StatefulWidget {
  final List<String> images;
  final int initialIndex;
  final Function(String)? onSave;
  
  const ImagePreview({
    Key? key,
    required this.images,
    this.initialIndex = 0,
    this.onSave,
  }) : super(key: key);
  
  @override
  State<ImagePreview> createState() => _ImagePreviewState();
}

组件接收图片URL列表、初始索引和保存回调。initialIndex指定初始显示的图片,onSave处理保存操作。

状态类中的手势控制:

dart 复制代码
class _ImagePreviewState extends State<ImagePreview> {
  late PageController _pageController;
  int _currentIndex = 0;
  double _scale = 1.0;
  Offset _offset = Offset.zero;
  
  @override
  void initState() {
    super.initState();
    _currentIndex = widget.initialIndex;
    _pageController = PageController(initialPage: widget.initialIndex);
  }
  
  void _resetTransform() {
    setState(() {
      _scale = 1.0;
      _offset = Offset.zero;
    });
  }
}

状态类管理当前图片索引、缩放比例和平移偏移。PageController控制图片切换,_resetTransform重置变换状态。

图片预览页面构建:

dart 复制代码
@override
Widget build(BuildContext context) {
  return Scaffold(
    backgroundColor: Colors.black,
    body: Stack(
      children: [
        GestureDetector(
          onTap: () => Navigator.pop(context),
          child: PageView.builder(
            controller: _pageController,
            itemCount: widget.images.length,
            onPageChanged: (index) {
              setState(() => _currentIndex = index);
              _resetTransform();
            },
            itemBuilder: (context, index) => _buildImageView(widget.images[index]),
          ),
        ),
        _buildTopBar(),
        _buildBottomIndicator(),
      ],
    ),
  );
}

预览页面使用黑色背景,PageView实现左右滑动切换图片。点击空白区域关闭预览,顶部显示操作栏,底部显示索引指示器。

可缩放图片视图:

dart 复制代码
Widget _buildImageView(String imageUrl) {
  return InteractiveViewer(
    minScale: 0.5,
    maxScale: 4.0,
    child: Center(
      child: Image.network(
        imageUrl,
        fit: BoxFit.contain,
        loadingBuilder: (context, child, loadingProgress) {
          if (loadingProgress == null) return child;
          return Center(
            child: CircularProgressIndicator(
              value: loadingProgress.expectedTotalBytes != null
                ? loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes!
                : null,
            ),
          );
        },
      ),
    ),
  );
}

InteractiveViewer提供缩放和平移功能,minScale和maxScale限制缩放范围。loadingBuilder显示加载进度,提升用户体验。

顶部操作栏:

dart 复制代码
Widget _buildTopBar() {
  return Positioned(
    top: 0,
    left: 0,
    right: 0,
    child: Container(
      padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top),
      decoration: BoxDecoration(
        gradient: LinearGradient(
          begin: Alignment.topCenter,
          end: Alignment.bottomCenter,
          colors: [Colors.black54, Colors.transparent],
        ),
      ),
      child: Row(
        children: [
          IconButton(
            icon: Icon(Icons.close, color: Colors.white),
            onPressed: () => Navigator.pop(context),
          ),
          Spacer(),
          Text(
            '${_currentIndex + 1}/${widget.images.length}',
            style: TextStyle(color: Colors.white),
          ),
          IconButton(
            icon: Icon(Icons.download, color: Colors.white),
            onPressed: () => widget.onSave?.call(widget.images[_currentIndex]),
          ),
        ],
      ),
    ),
  );
}

顶部操作栏使用渐变背景,显示关闭按钮、图片索引和保存按钮。MediaQuery获取状态栏高度,避免内容被遮挡。

OpenHarmony鸿蒙端实现

图片预览组件的基础结构:

typescript 复制代码
@Component
struct ImagePreview {
  @Prop images: string[] = []
  @Prop initialIndex: number = 0
  @State currentIndex: number = 0
  @State scale: number = 1
  @State offsetX: number = 0
  @State offsetY: number = 0
  
  private swiperController: SwiperController = new SwiperController()
  private onSave: (url: string) => void = () => {}
  private onClose: () => void = () => {}
  
  aboutToAppear() {
    this.currentIndex = this.initialIndex
  }
}

使用@State管理当前索引和变换状态,SwiperController控制图片切换。

图片预览页面构建:

typescript 复制代码
build() {
  Stack() {
    Swiper(this.swiperController) {
      ForEach(this.images, (image: string, index: number) => {
        this.ImageView(image)
      })
    }
    .index(this.currentIndex)
    .indicator(false)
    .loop(false)
    .onChange((index: number) => {
      this.currentIndex = index
      this.resetTransform()
    })
    
    this.TopBar()
    this.BottomIndicator()
  }
  .width('100%')
  .height('100%')
  .backgroundColor(Color.Black)
}

Swiper组件实现左右滑动切换,indicator设为false隐藏默认指示器。onChange监听切换事件更新当前索引。

可缩放图片视图:

typescript 复制代码
@Builder
ImageView(imageUrl: string) {
  Column() {
    Image(imageUrl)
      .width('100%')
      .height('100%')
      .objectFit(ImageFit.Contain)
      .scale({ x: this.scale, y: this.scale })
      .translate({ x: this.offsetX, y: this.offsetY })
  }
  .width('100%')
  .height('100%')
  .justifyContent(FlexAlign.Center)
  .gesture(
    GestureGroup(GestureMode.Parallel,
      PinchGesture()
        .onActionUpdate((event: GestureEvent) => {
          this.scale = Math.max(0.5, Math.min(4, this.scale * event.scale))
        }),
      PanGesture()
        .onActionUpdate((event: GestureEvent) => {
          this.offsetX += event.offsetX
          this.offsetY += event.offsetY
        }),
      TapGesture({ count: 2 })
        .onAction(() => {
          if (this.scale > 1) {
            this.resetTransform()
          } else {
            this.scale = 2
          }
        })
    )
  )
}

图片视图支持捏合缩放、平移和双击放大。GestureGroup组合多个手势,PinchGesture处理缩放,PanGesture处理平移,TapGesture处理双击。

顶部操作栏:

typescript 复制代码
@Builder
TopBar() {
  Row() {
    Image($r('app.media.close'))
      .width(24)
      .height(24)
      .fillColor(Color.White)
      .onClick(() => this.onClose())
    
    Blank()
    
    Text(`${this.currentIndex + 1}/${this.images.length}`)
      .fontSize(16)
      .fontColor(Color.White)
    
    Blank()
    
    Image($r('app.media.download'))
      .width(24)
      .height(24)
      .fillColor(Color.White)
      .onClick(() => this.onSave(this.images[this.currentIndex]))
  }
  .width('100%')
  .padding({ left: 16, right: 16, top: 48, bottom: 16 })
  .linearGradient({
    angle: 180,
    colors: [['#80000000', 0], ['#00000000', 1]]
  })
  .position({ x: 0, y: 0 })
}

顶部操作栏使用渐变背景,显示关闭按钮、图片索引和保存按钮。position定位在顶部。

底部索引指示器:

typescript 复制代码
@Builder
BottomIndicator() {
  Row() {
    ForEach(this.images, (image: string, index: number) => {
      Circle()
        .width(this.currentIndex === index ? 8 : 6)
        .height(this.currentIndex === index ? 8 : 6)
        .fill(this.currentIndex === index ? Color.White : '#80FFFFFF')
        .margin({ left: 4, right: 4 })
    })
  }
  .width('100%')
  .justifyContent(FlexAlign.Center)
  .padding({ bottom: 32 })
  .position({ x: 0, y: '90%' })
}

底部指示器使用圆点显示当前图片位置,当前图片对应的圆点更大更亮。position定位在底部。

总结

本文详细介绍了Flutter和OpenHarmony平台上图片预览组件的开发方法。图片预览是OA系统中查看附件的常用功能,需要支持缩放、平移、多图切换等操作。Flutter使用InteractiveViewer和PageView,鸿蒙使用手势组合和Swiper。开发者需要注意手势冲突处理和加载状态的显示。

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

相关推荐
极客小云2 小时前
【IEEE Transactions系列期刊全览:计算机领域核心期刊深度解析】
android·论文阅读·python
2501_946675642 小时前
Flutter与OpenHarmony打卡消息提示组件
flutter
wanghowie2 小时前
02.01 Spring Boot|自动配置机制深度解析
android·spring boot·后端
一起搞IT吧2 小时前
三方相机问题分析十一:【手电筒回调异常】手电筒打开3档时,达到档位控制温度,手电筒二级界面中档位为0
android·图像处理·数码相机
xu_duo_i2 小时前
vue3+element-plus图片上传,前端压缩(纯函数,无插件)
前端·javascript·vue.js
2501_924064112 小时前
2025年移动应用渗透测试流程方案及iOS安卓测试方法对比
android·ios
POLITE32 小时前
Leetcode 240. 搜索二维矩阵 II JavaScript (Day 9)
javascript·leetcode·矩阵
千里马学框架2 小时前
安卓14-16车机手机仿小米su7三分屏实战项目专题
android·智能手机·framework·分屏·车载·小米汽车·三分屏
走在路上的菜鸟3 小时前
Android学Flutter学习笔记 第二节 Android视角认知Flutter(resource,生命周期,layout)
android·学习·flutter