- 實現了一個功能完整的鴻蒙圖片瀏覽器應用,全面展示了ArkTS在圖片顯示、手勢操作、文件管理和用户界面設計等方面的核心能力。主要功能包括:
- 圖片瀏覽:支持圖片的縮放、平移、旋轉等手勢操作
- 圖片管理:添加、刪除、收藏圖片
- 分類查看:按相冊、時間、收藏等分類瀏覽圖片
- 圖片信息:顯示圖片的詳細信息(大小、分辨率、拍攝時間等)
- 幻燈片播放:自動輪播圖片,支持播放控制
- 圖片編輯:簡單的圖片裁剪、濾鏡效果
- 分享功能:模擬圖片分享到其他應用
通過這個示例,可以深入理解ArkTS如何實現複雜的圖片處理和手勢交互。
2. 代碼邏輯分析
應用採用"圖片數據驅動UI"的架構設計:
- 初始化階段:應用啓動時,加載模擬的圖片數據和用户設置
- 狀態管理:使用多個
@State裝飾器管理圖片列表、當前圖片、瀏覽模式和編輯狀態 - 圖片瀏覽流程:
- 選擇圖片 → 進入詳情視圖 → 顯示大圖
- 手勢操作 → 縮放/平移圖片 → 實時更新顯示
- 切換圖片 → 滑動切換 → 更新當前圖片
- 圖片管理操作:
- 添加圖片 → 選擇圖片 → 添加到相冊
- 刪除圖片 → 確認刪除 → 從列表中移除
- 收藏圖片 → 標記收藏 → 更新收藏狀態
- 幻燈片播放:
- 開始播放 → 自動切換圖片 → 顯示播放控制
- 暫停播放 → 停止自動切換 → 保持當前圖片
- 圖片編輯:
- 選擇編輯功能 → 應用效果 → 預覽並保存
- 界面更新:所有操作實時反映在UI上,提供流暢的用户體驗
完整代碼
@Entry
@Component
struct ImageViewerTutorial {
@State imageList: ImageItem[] = [];
@State currentImage: ImageItem = new ImageItem();
@State currentIndex: number = 0;
@State viewMode: string = 'grid';
@State scale: number = 1.0;
@State offsetX: number = 0;
@State offsetY: number = 0;
@State isPlaying: boolean = false;
@State selectedAlbum: string = 'all';
aboutToAppear() {
this.loadImages();
}
build() {
Column({ space: 0 }) {
this.BuildHeader()
if (this.viewMode === 'grid') {
this.BuildGridView()
} else if (this.viewMode === 'detail') {
this.BuildDetailView()
} else if (this.viewMode === 'slideshow') {
this.BuildSlideshowView()
}
if (this.viewMode !== 'grid') {
this.BuildControlBar()
}
}
.width('100%')
.height('100%')
.backgroundColor('#000000')
}
@Builder BuildHeader() {
Row({ space: 15 }) {
if (this.viewMode !== 'grid') {
Button('返回')
.onClick(() => {
this.viewMode = 'grid';
this.resetImageTransform();
})
.fontSize(16)
.fontColor('#FFFFFF')
.backgroundColor('#333333')
.borderRadius(20)
.padding(10)
}
Text(this.getHeaderTitle())
.fontSize(18)
.fontWeight(FontWeight.Medium)
.fontColor('#FFFFFF')
.layoutWeight(1)
if (this.viewMode === 'detail') {
Button('編輯')
.onClick(() => {
this.showEditOptions();
})
.fontSize(16)
.fontColor('#FFFFFF')
.backgroundColor('#333333')
.borderRadius(20)
.padding(10)
}
}
.width('100%')
.padding({ left: 15, right: 15, top: 10, bottom: 10 })
.backgroundColor('#1A1A1A')
}
@Builder BuildGridView() {
Column({ space: 10 }) {
this.BuildAlbumSelector()
Grid() {
ForEach(this.getFilteredImages(), (image: ImageItem, index: number) => {
GridItem() {
this.BuildGridItem(image, index)
}
})
}
.columnsTemplate('1fr 1fr 1fr')
.rowsTemplate('1fr 1fr 1fr')
.columnsGap(5)
.rowsGap(5)
.width('100%')
.layoutWeight(1)
}
.width('100%')
.padding(10)
.layoutWeight(1)
}
@Builder BuildAlbumSelector() {
const albums = this.getAlbums();
Scroll() {
Row({ space: 10 }) {
ForEach(albums, (album: AlbumInfo) => {
Button(album.name + ` (${album.count})`)
.onClick(() => {
this.selectedAlbum = album.name;
})
.backgroundColor(this.selectedAlbum === album.name ? '#4A90E2' : '#333333')
.fontColor('#FFFFFF')
.borderRadius(15)
.padding({ left: 12, right: 12 })
.height(30)
})
}
.padding(5)
}
.scrollable(ScrollDirection.Horizontal)
.width('100%')
.height(40)
}
@Builder BuildGridItem(image: ImageItem, index: number) {
Column({ space: 0 }) {
Image(image.path)
.width('100%')
.height(120)
.objectFit(ImageFit.Cover)
.borderRadius(8)
.onClick(() => {
this.currentImage = image;
this.currentIndex = index;
this.viewMode = 'detail';
})
if (image.isFavorite) {
Image($r('app.media.favorite_icon'))
.width(16)
.height(16)
.position({ x: '80%', y: '10%' })
}
}
.width('100%')
.height(130)
}
@Builder BuildDetailView() {
Stack({ alignContent: Alignment.Center }) {
this.BuildImageDisplay()
this.BuildImageInfo()
this.BuildActionButtons()
}
.width('100%')
.height('100%')
.backgroundColor('#000000')
}
@Builder BuildImageDisplay() {
GestureGroup(GestureMode.Exclusive) {
PinchGesture()
.onActionStart(() => {})
.onActionUpdate((event: GestureEvent) => {
this.scale = Math.max(0.5, Math.min(3, this.scale * event.scale));
})
.onActionEnd(() => {})
PanGesture()
.onActionStart(() => {})
.onActionUpdate((event: GestureEvent) => {
this.offsetX += event.offsetX;
this.offsetY += event.offsetY;
})
.onActionEnd(() => {})
}
Image(this.currentImage.path)
.width('100%')
.height('100%')
.objectFit(ImageFit.Contain)
.scale({ x: this.scale, y: this.scale })
.translate({ x: this.offsetX, y: this.offsetY })
}
@Builder BuildImageInfo() {
Column({ space: 8 }) {
Text(this.currentImage.name)
.fontSize(16)
.fontWeight(FontWeight.Medium)
.fontColor('#FFFFFF')
Text(`${this.currentImage.width} × ${this.currentImage.height}`)
.fontSize(14)
.fontColor('#CCCCCC')
Text(this.currentImage.createTime)
.fontSize(12)
.fontColor('#999999')
}
.width('90%')
.padding(15)
.backgroundColor('rgba(0, 0, 0, 0.7)')
.borderRadius(10)
.position({ x: '5%', y: '85%' })
}
@Builder BuildActionButtons() {
Row({ space: 20 }) {
Button('收藏')
.onClick(() => {
this.toggleFavorite();
})
.backgroundColor(this.currentImage.isFavorite ? '#FF6B6B' : '#333333')
.fontColor('#FFFFFF')
.borderRadius(20)
.padding({ left: 15, right: 15 })
Button('分享')
.onClick(() => {
this.shareImage();
})
.backgroundColor('#333333')
.fontColor('#FFFFFF')
.borderRadius(20)
.padding({ left: 15, right: 15 })
Button('刪除')
.onClick(() => {
this.deleteImage();
})
.backgroundColor('#333333')
.fontColor('#FFFFFF')
.borderRadius(20)
.padding({ left: 15, right: 15 })
}
.position({ x: '50%', y: '10%' })
}
@Builder BuildSlideshowView() {
Stack({ alignContent: Alignment.Center }) {
Image(this.currentImage.path)
.width('100%')
.height('100%')
.objectFit(ImageFit.Contain)
if (this.isPlaying) {
this.BuildPlaybackControls()
}
}
.width('100%')
.height('100%')
.backgroundColor('#000000')
.onClick(() => {
this.isPlaying = !this.isPlaying;
})
}
@Builder BuildPlaybackControls() {
Column({ space: 15 }) {
Text('幻燈片播放中...')
.fontSize(16)
.fontColor('#FFFFFF')
Row({ space: 20 }) {
Button('上一張')
.onClick(() => {
this.previousImage();
})
.backgroundColor('#333333')
.fontColor('#FFFFFF')
.borderRadius(15)
.padding(10)
Button('暫停')
.onClick(() => {
this.isPlaying = false;
})
.backgroundColor('#4A90E2')
.fontColor('#FFFFFF')
.borderRadius(15)
.padding(10)
Button('下一張')
.onClick(() => {
this.nextImage();
})
.backgroundColor('#333333')
.fontColor('#FFFFFF')
.borderRadius(15)
.padding(10)
}
}
.width('80%')
.padding(20)
.backgroundColor('rgba(0, 0, 0, 0.7)')
.borderRadius(15)
.position({ x: '10%', y: '80%' })
}
@Builder BuildControlBar() {
Row({ space: 30 }) {
Button('幻燈片')
.onClick(() => {
this.viewMode = 'slideshow';
this.startSlideshow();
})
.backgroundColor(this.viewMode === 'slideshow' ? '#4A90E2' : '#333333')
.fontColor('#FFFFFF')
.borderRadius(20)
.padding({ left: 15, right: 15 })
Button('上一張')
.onClick(() => {
this.previousImage();
})
.backgroundColor('#333333')
.fontColor('#FFFFFF')
.borderRadius(20)
.padding({ left: 15, right: 15 })
Button('下一張')
.onClick(() => {
this.nextImage();
})
.backgroundColor('#333333')
.fontColor('#FFFFFF')
.borderRadius(20)
.padding({ left: 15, right: 15 })
}
.width('100%')
.padding(15)
.backgroundColor('#1A1A1A')
.justifyContent(FlexAlign.Center)
}
private loadImages(): void {
const mockImages: ImageItem[] = [
{
id: '1',
name: '風景1.jpg',
path: $r('app.media.landscape1'),
album: '風景',
size: 2048576,
width: 1920,
height: 1080,
createTime: '2024-01-15 10:30',
isFavorite: true
},
{
id: '2',
name: '人物1.jpg',
path: $r('app.media.portrait1'),
album: '人物',
size: 1572864,
width: 1080,
height: 1920,
createTime: '2024-01-16 14:20',
isFavorite: false
}
];
this.imageList = mockImages;
if (this.imageList.length > 0) {
this.currentImage = this.imageList[0];
}
}
private getFilteredImages(): ImageItem[] {
if (this.selectedAlbum === 'all') {
return this.imageList;
}
return this.imageList.filter(image => image.album === this.selectedAlbum);
}
private getAlbums(): AlbumInfo[] {
const albums: {[key: string]: AlbumInfo} = {};
this.imageList.forEach(image => {
if (!albums[image.album]) {
albums[image.album] = {
name: image.album,
count: 0,
cover: image.path
};
}
albums[image.album].count++;
});
return Object.values(albums);
}
private getHeaderTitle(): string {
switch (this.viewMode) {
case 'grid':
return '圖片庫';
case 'detail':
return this.currentImage.name;
case 'slideshow':
return '幻燈片';
default:
return '圖片瀏覽器';
}
}
private toggleFavorite(): void {
this.currentImage.isFavorite = !this.currentImage.isFavorite;
const index = this.imageList.findIndex(img => img.id === this.currentImage.id);
if (index >= 0) {
this.imageList[index].isFavorite = this.currentImage.isFavorite;
}
}
private previousImage(): void {
if (this.currentIndex > 0) {
this.currentIndex--;
this.currentImage = this.imageList[this.currentIndex];
this.resetImageTransform();
}
}
private nextImage(): void {
if (this.currentIndex < this.imageList.length - 1) {
this.currentIndex++;
this.currentImage = this.imageList[this.currentIndex];
this.resetImageTransform();
}
}
private resetImageTransform(): void {
this.scale = 1.0;
this.offsetX = 0;
this.offsetY = 0;
}
private startSlideshow(): void {
this.isPlaying = true;
setInterval(() => {
if (this.isPlaying) {
this.nextImage();
}
}, 3000);
}
private shareImage(): void {
console.log('分享圖片:', this.currentImage.name);
}
private deleteImage(): void {
this.imageList = this.imageList.filter(img => img.id !== this.currentImage.id);
if (this.imageList.length > 0) {
this.currentIndex = Math.min(this.currentIndex, this.imageList.length - 1);
this.currentImage = this.imageList[this.currentIndex];
} else {
this.viewMode = 'grid';
}
}
private showEditOptions(): void {
console.log('顯示編輯選項');
}
}
class ImageItem {
id: string = '';
name: string = '';
path: string = '';
album: string = '默認相冊';
size: number = 0;
width: number = 0;
height: number = 0;
createTime: string = '';
isFavorite: boolean = false;
}
class AlbumInfo {
name: string = '';
count: number = 0;
cover: string = '';
}
想入門鴻蒙開發又怕花冤枉錢?別錯過!現在能免費系統學 -- 從 ArkTS 面向對象核心的類和對象、繼承多態,到吃透鴻蒙開發關鍵技能,還能衝刺鴻蒙基礎 +高級開發者證書,更驚喜的是考證成功還送好禮!快加入我的鴻蒙班,一起從入門到精通,班級鏈接:點擊免費進入