Tiếp theo bài viết trước: Hướng Dẫn Thực Chiến Thành Phần RcImage Trong HarmonyOS6 - Phần 1
Sáu: Thực Chiến Xem Trước Hình Ảnh
6.1 Kiến Trúc Chức Năng Xem Trước
Hệ thống xem trước hình ảnh
├─ 🔹 Cách kích hoạt
│ ├─ Nhấp vào hình ảnh
│ └─ previewable: true
│
├─ 🔹 Chế độ xem trước
│ ├─ Xem trước một hình
│ └─ Xem trước danh sách (hỗ trợ chuyển đổi)
│
├─ 🔹 Tính năng tương tác
│ ├─ Điều khiển phóng to (+ / -)
│ ├─ Chuyển đổi hình (< / >)
│ └─ Đóng xem trước (X / lớp phủ)
│
└─ 🔹 Tùy chọn cấu hình
├─ Hiển thị lớp phủ
├─ Hiển thị nút đóng
└─ Cài đặt phạm vi zoom
6.2 Xem Trước Một Hình Ảnh
Ứng dụng: Hình minh họa bài viết, chi tiết sản phẩm, hiển thị giấy tờ
this.TieuDeDe('Nhấp để xem (một hình)')
HinhAnh({
nguonHinh: 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=800',
rongHinh: 300,
caoHinh: 200,
hinhDang: 'tròn',
banKinh: 12,
coXemTruoc: true,
hienThiChuThich: true,
noiDungChuThich: 'Nhấp để xem lớn',
khiMoXemTruoc: () => {
console.log('Mở xem trước')
},
khiDongXemTruoc: () => {
console.log('Đóng xem trước')
}
})
Điểm kỹ thuật:
previewable: trueKích hoạt chức năng xem trướconPreviewOpenLắng nghe sự kiện mở xem trướconPreviewCloseLắng nghe sự kiện đóng xem trước
Ví dụ thực tế - Xem trước hình minh họa bài viết:
@Builder
NoiDungBaiViet() {
Column { space: 16 } {
Text('Thực Chiến HarmonyOS6')
.fontSize(24)
.fontWeight(FontWeight.Bold)
Text('Hình ảnh có thể nhấp để xem lớn')
.fontSize(14)
.fontColor('#909399')
// Hình minh họa 1
HinhAnh({
nguonHinh: 'https://example.com/hinh-bai-viet-1.jpg',
rongHinh: '100%',
caoHinh: 250,
hinhDang: 'tròn',
banKinh: 12,
coXemTruoc: true,
hienThiChuThich: true,
noiDungChuThich: 'Hình 1: Sơ đồ kiến trúc hệ thống'
})
Text('Nội dung chính...')
.fontSize(16)
.lineHeight(28)
// Hình minh họa 2
HinhAnh({
nguonHinh: 'https://example.com/hinh-bai-viet-2.jpg',
rongHinh: '100%',
caoHinh: 250,
hinhDang: 'tròn',
banKinh: 12,
coXemTruoc: true,
hienThiChuThich: true,
noiDungChuThich: 'Hình 2: Hiệu quả chạy'
})
}
.width('100%')
.padding(16)
}
6.3 Xem Trước Danh Sách Hình Ảnh (tính năng cốt lõi)
Ứng dụng: Album ảnh, nhiều hình sản phẩm, thư viện hình ảnh
this.TieuDeDe('Xem trước danh sách hình (hỗ trợ chuyển trái/phải)')
Text('Nhấp vào bất kỳ hình nào để xem, hỗ trợ zoom và chuyển đổi')
.fontSize(14)
.fontColor('#909399')
.margin({ bottom: 10 })
Row { space: 10 } {
ForEach(this.danhSachHinh, (hinh: string, index: number) => {
HinhAnh({
nguonHinh: hinh,
rongHinh: 80,
caoHinh: 80,
hinhDang: 'tròn',
banKinh: 8,
kichThuocHinh: 'cover',
coXemTruoc: true,
danhSachXemTruoc: this.danhSachHinh, // Danh sách hình xem trước
chiSoHienTai: index, // Chỉ số hình hiện tại
tuyenChonXemTruoc: {
hienThiLopPhu: true, // Hiển thị lớp phủ
hienThiNutDong: true, // Hiển thị nút đóng
tyLeBanDau: 1, // Tỷ lệ zoom ban đầu
tyLeNhoNhat: 0.5, // Tỷ lệ zoom nhỏ nhất
tyLeLonNhat: 3 // Tỷ lệ zoom lớn nhất
}
})
})
}
.width('100%')
.justifyContent(FlexAlign.SpaceAround)
Tham số quan trọng:
| Tham số | Loại | Mô tả | Giá trị mặc định |
|---|---|---|---|
previewList |
string[] | Danh sách hình xem trước | Bắt buộc |
previewIndex |
number | Chỉ số hình hiện tại | Bắt buộc |
previewOptions |
object | Đối tượng cấu hình xem trước | Tùy chọn |
Chi tiết cấu hình previewOptions:
| Thiết lập | Loại | Mô tả | Giá trị đề xuất |
|---|---|---|---|
showMask |
boolean | Hiển thị lớp phủ | true |
showClose |
boolean | Hiển thị nút đóng | true |
initialScale |
number | Tỷ lệ zoom ban đầu | 1 |
minScale |
number | Tỷ lệ zoom nhỏ nhất | 0.5 |
maxScale |
number | Tỷ lệ zoom lớn nhất | 3 |
Ví dụ thực tế - Xem trước nhiều hình sản phẩm:
@State danhSachHinhSanPham: string[] = [
'https://example.com/san-pham-1.jpg',
'https://example.com/san-pham-2.jpg',
'https://example.com/san-pham-3.jpg',
'https://example.com/san-pham-4.jpg'
]
@State chiSoXemTruocHienTai: number = 0
@Builder
ThuVienSanPham() {
Column { space: 12 } {
// Hình chính xem trước
HinhAnh({
nguonHinh: this.danhSachHinhSanPham[this.chiSoXemTruocHienTai],
rongHinh: '100%',
caoHinh: 375,
kichThuocHinh: 'contain',
mauNen: '#F5F5F5',
coXemTruoc: true,
danhSachXemTruoc: this.danhSachHinhSanPham,
chiSoHienTai: this.chiSoXemTruocHienTai,
tuyenChonXemTruoc: {
hienThiLopPhu: true,
hienThiNutDong: true,
tyLeBanDau: 1,
tyLeNhoNhat: 0.5,
tyLeLonNhat: 4 // Cho phép zoom lớn hơn cho hình sản phẩm
}
})
// Danh sách hình thu nhỏ
Row { space: 8 } {
ForEach(this.danhSachHinhSanPham, (hinh: string, index: number) => {
HinhAnh({
nguonHinh: hinh,
rongHinh: 60,
caoHinh: 60,
hinhDang: 'tròn',
banKinh: 6,
kichThuocHinh: 'cover',
doDayVien: this.chiSoXemTruocHienTai === index ? 2 : 0,
mauVien: '#409EFF',
khiHinhDuocCham: () => {
this.chiSoXemTruocHienTai = index
}
})
})
}
.width('100%')
.justifyContent(FlexAlign.Start)
}
.width('100%')
.padding(16)
}
6.4 Giải Thích Chức Năng Xem Trước
this.TieuDeDe('Giải thích chức năng xem trước')
Column { space: 8 } {
this.TextThongTin('• Nhấp vào hình để mở xem trước')
this.TextThongTin('• Nhấp vào lớp phủ hoặc nút đóng để thoát')
this.TextThongTin('• Sử dụng nút + / - để phóng to/thu nhỏ hình')
this.TextThongTin('• Sử dụng nút < / > để chuyển hình (chế độ danh sách)')
}
.alignItems(HorizontalAlign.Start)
.width('100%')
.padding(16)
.backgroundColor('#FFF9E6')
.borderRadius(8)
Tóm tắt tương tác:
| Hành động | Cách kích hoạt | Chức năng |
|---|---|---|
| **Mở xem trước** | Nhấp vào hình | Vào chế độ xem trước toàn màn hình |
| **Đóng xem trước** | Nhấp lớp phủ/nút đóng | Thoát chế độ xem trước |
| **Phóng to** | Nhấp nút + | Phóng to hình theo tỷ lệ |
| **Thu nhỏ** | Nhấp nút - | Thu nhỏ hình theo tỷ lệ |
| **Hình trước** | Nhấp nút < | Chuyển sang hình trước |
| **Hình sau** | Nhấp nút > | Chuyển sang hình sau |
Bảy: Thực Chiến Kiểu Dạng Viền
7.1 Tham Số Hệ Thống Viền
| Tham số | Loại | Mô tả | Giá trị mặc định |
|---|---|---|---|
rcBorderWidth |
number | Độ rộng viền | 0 |
rcBorderColor |
string | Màu viền | '#000000' |
rcBorderStyle |
BorderStyle | Kiểu viền | Solid |
rcPadding |
number | Đệm trong | 0 |
7.2 Viền Đường Thẳng
Ứng dụng: Thẻ sản phẩm, nhấn mạnh
this.TieuDeDe('Có viền')
HinhAnh({
nguonHinh: 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=500',
rongHinh: 300,
caoHinh: 200,
doDayVien: 2,
mauVien: '#409eff',
kieuVien: BorderStyle.Solid
})
Quy tắc thiết kế:
- Độ rộng viền: 1-3px
- Màu sắc: Màu thương hiệu hoặc màu chủ đề
- Phù hợp cho hình cần nhấn mạnh
7.3 Viền Đường Gạch Ngang
Ứng dụng: Bản nháp, trạng thái chờ tải
this.TieuDeDe('Viền gạch ngang')
HinhAnh({
nguonHinh: 'https://images.unsplash.com/photo-1469474968028-56623f02e42e?w=500',
rongHinh: 300,
caoHinh: 200,
doDayVien: 2,
mauVien: '#67c23a',
kieuVien: BorderStyle.Dashed
})
Ví dụ thực tế - Chỗ tải lên hình:
@Builder
ChoTaiLenHinh() {
Stack() {
HinhAnh({
nguonHinh: this.hinhDuocTai || $r('app.media.upload_placeholder'),
rongHinh: 200,
caoHinh: 200,
doDayVien: 2,
mauVien: '#DCDFE6',
kieuVien: BorderStyle.Dashed,
khiHinhDuocCham: () => {
this.hienThiChonHinh()
}
})
if (!this.hinhDuocTai) {
Column { space: 8 } {
Text('+')
.fontSize(48)
.fontColor('#C0C4CC')
Text('Nhấp để tải lên')
.fontSize(14)
.fontColor('#909399')
}
}
}
}
7.4 Viền Điểm
Ứng dụng: Thiết kế đặc biệt, hiệu ứng trang trí
this.TieuDeDe('Viền điểm')
HinhAnh({
nguonHinh: 'https://images.unsplash.com/photo-1501785888041-af3ef285b470?w=500',
rongHinh: 300,
caoHinh: 200,
doDayVien: 3,
mauVien: '#e6a23c',
kieuVien: BorderStyle.Dotted
})
7.5 Hình Tròn + Viền
Ứng dụng: Avatar người dùng VIP, nhận dạng đặc biệt
this.TieuDeDe('Hình tròn + viền')
HinhAnh({
nguonHinh: 'https://images.unsplash.com/photo-1518173946687-a4c8892bbd9f?w=500',
rongHinh: 150,
caoHinh: 150,
hinhDang: 'circle',
kichThuocHinh: 'cover',
doDayVien: 4,
mauVien: '#f56c6c',
kieuVien: BorderStyle.Solid
})
Ví dụ thực tế - Avatar người dùng VIP:
@Builder
AvatarNguoiDungVIP(thongTinNguoiDung: ThongTinNguoiDung) {
Stack { alignContent: Alignment.BottomEnd } {
HinhAnh({
nguonHinh: thongTinNguoiDung.avatarUrl,
rongHinh: 80,
caoHinh: 80,
hinhDang: 'circle',
kichThuocHinh: 'cover',
doDayVien: 3,
mauVien: thongTinNguoiDung.laVIP ? '#FFD700' : '#E0E0E0',
kieuVien: BorderStyle.Solid
})
if (thongTinNguoiDung.laVIP) {
Text('VIP')
.fontSize(10)
.fontColor('#FFFFFF')
.backgroundColor('#FFD700')
.padding({ left: 4, right: 4, top: 2, bottom: 2 })
.borderRadius(4)
.offset({ x: -5, y: -5 })
}
}
}
7.6 Góc Tròn + Viền + Nền
Ứng dụng: Thiết kế thẻ, hiển thị tinh tế
this.TieuDeDe('Góc tròn + viền + nền')
HinhAnh({
nguonHinh: 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=500',
rongHinh: 300,
caoHinh: 200,
hinhDang: 'round',
banKinh: 16,
mauNen: '#E8F4FF',
doDayVien: 2,
mauVien: '#409eff',
kieuVien: BorderStyle.Solid,
rcPadding: 8
})
Điểm nổi bật thiết kế:
- Sử dụng
rcPaddingtạo hiệu ứng đệm trong bgColorvàrcBorderColortương hỗ- Phù hợp cho hiển thị sản phẩm cao cấp
7.7 Thực Chiến Sự Kiện Nhấp
Ứng dụng: Phản hồi tương tác, hiển thị hộp thoại
this.TieuDeDe('Sự kiện nhấp')
HinhAnh({
nguonHinh: 'https://images.unsplash.com/photo-1469474968028-56623f02e42e?w=500',
rongHinh: 300,
caoHinh: 200,
hinhDang: 'round',
banKinh: 12,
hienThiChuThich: true,
noiDungChuThich: 'Nhấp vào tôi',
khiHinhDuocCham: () => {
this.getUIContext().getPromptAction().showDialog({
title: 'Thông báo',
message: 'Hình ảnh đã được nhấn!',
buttons: [
{
text: 'Đồng ý',
color: '#409EFF'
}
]
})
}
})
Ví dụ thực tế - Menu thao tác hình ảnh:
@Builder
HinhAnhCoMenu(duongDanHinh: string) {
HinhAnh({
nguonHinh: duongDanHinh,
rongHinh: 300,
caoHinh: 200,
hinhDang: 'round',
banKinh: 12,
khiHinhDuocCham: () => {
this.getUIContext().getPromptAction().showActionMenu({
title: 'Thao tác hình',
buttons: [
{
text: 'Lưu vào thư viện',
color: '#409EFF'
},
{
text: 'Chia sẻ bạn bè',
color: '#67C23A'
},
{
text: 'Xóa hình',
color: '#F56C6C'
},
{
text: 'Hủy',
color: '#909399'
}
]
})
}
})
}
Mười Một: Các Vấn Đề Thường Gặp và Giải Pháp
11.1 Vấn Đề Hiển Thị Hình Ảnh
Vấn đề 1: Hình ảnh bị méo
Nguyên nhân: Chọn chế độ điền không phù hợp
Giải pháp:
// ❌ Sai: Sử dụng fill gây méo
HinhAnh({
nguonHinh: avatarNguoiDung,
rongHinh: 100,
caoHinh: 100,
kichThuocHinh: 'fill'
})
// ✅ Đúng: Sử dụng cover giữ tỷ lệ
HinhAnh({
nguonHinh: avatarNguoiDung,
rongHinh: 100,
caoHinh: 100,
kichThuocHinh: 'cover',
hinhDang: 'circle'
})
Vấn đề 2: Hình tròn hiển thị không đầy đủ
Nguyên nhân: Không sử dụng chế độ điền cover
Giải pháp:
HinhAnh({
nguonHinh: avatar,
rongHinh: 80,
caoHinh: 80,
hinhDang: 'circle',
kichThuocHinh: 'cover' // Bắt buộc phải đặt
})
11.2 Vấn Đề Hiệu Năng
Vấn đề 3: Danh sách dài bị giật lag
Nguyên nhân: Tải quá nhiều hình ảnh cùng lúc
Giải pháp:
List() {
LazyForEach(this.nguonHinhDuLieu, (hinh: string, index: number) => {
ListItem() {
HinhAnh({
nguonHinh: hinh + '?w=200', // Tải kích thước nhỏ
rongHinh: 200,
caoHinh: 200
})
}
})
}
.cachedCount(5) // Lưu 5 mục
Vấn đề 4: Bộ nhớ sử dụng cao
Nguyên nhân: Bộ nhớ cache hình ảnh không được giải phóng
Giải pháp:
aboutToDisappear() {
this.danhSachHinh = []
this.boNhoHinhAnh.clear()
}
11.3 Vấn Đề Tương Tác
Vấn đề 5: Chuyển đổi danh sách xem trước thất bại
Nguyên nhân: previewIndex không được đặt đúng
Giải pháp:
ForEach(this.hinhs, (hinh: string, index: number) => {
HinhAnh({
nguonHinh: hinh,
coXemTruoc: true,
danhSachXemTruoc: this.hinhs,
chiSoHienTai: index // Phải truyền chỉ số hiện tại
})
})
11.4 Danh Sách Thực Hành Tốt Nhất
Bắt buộc tuân thủ
| Quy tắc | Mô tả | Lý do |
|---|---|---|
| **Chỉ định kích thước** | Luôn đặt imageWidth và imageHeight | Tránh rung lưới |
| **Xử lý lỗi** | Mở showError cho hình mạng | Nâng cao trải nghiệm |
| **Chế độ điền** | Chọn imageFit phù hợp | Tránh méo |
| **Cấu hình xem trước** | Danh sách xem trước phải đặt previewList | Trải nghiệm đầy đủ |
️ Đề xuất tuân thủ
| Đề xuất | Mô tả | Lợi ích |
|---|---|---|
| **Sử dụng góc tròn** | Dùng góc 8-16 để tăng tính thẩm mỹ | Phong cách thiết kế hiện đại |
| **Trạng thái tải** | Mở showLoading để thông báo người dùng | Giảm lo lắng chờ đợi |
| **Trang trí viền** | Thêm viền cho hình quan trọng | Phân cấp rõ ràng |
| **Phản hồi nhấp** | Cung cấp sự kiện nhấp cho hình tương tác | Trải nghiệm tương tác đầy đủ |
️ Cấm thực hiện
| Cấm | Lý do | Giải pháp thay thế |
|---|---|---|
| **Không đặt kích thước** | Gây rối loạn bố cục | Chỉ định rõ ràng rộng cao |
| **Tải hình quá lớn** | Rủi ro tràn bộ nhớ | Sử dụng CDN cắt ảnh |
| **Lạm dụng xem trước** | Ảnh hưởng hiệu năng | Chỉ kích hoạt khi cần |
| **Bỏ qua lỗi** | Trống ảnh phá vỡ trải nghiệm | Mở showError |
Phụ Lục: Tài Liệu Nhanh
A.1 Bảng Tham Số Thường Dùng
| Tham số | Loại | Giá trị thường dùng | Tần suất sử dụng |
|---|---|---|---|
imageSrc |
string/Resource | URL / $r() | ⭐⭐⭐⭐⭐ |
imageWidth |
number/string | 200 / '100%' | ⭐⭐⭐⭐⭐ |
imageHeight |
number | 200 | ⭐⭐⭐⭐⭐ |
imageFit |
string | cover / contain | ⭐⭐⭐⭐ |
imageShape |
string | square / circle / round | ⭐⭐⭐⭐ |
imageRadius |
number | 8 / 16 | ⭐⭐⭐ |
previewable |
boolean | true / false | ⭐⭐⭐ |
showLoading |
boolean | true | ⭐⭐⭐ |
showError |
boolean | true | ⭐⭐⭐ |
A.2 Đoạn Mã Cho Tình Huển Điển Hình
Avatar người dùng
HinhAnh({
nguonHinh: duongDanAvatar,
rongHinh: 48,
caoHinh: 48,
hinhDang: 'circle',
kichThuocHinh: 'cover'
})
Hình thu nhỏ sản phẩm
HinhAnh({
nguonHinh: hinhSanPham,
rongHinh: 120,
caoHinh: 120,
hinhDang: 'round',
banKinh: 8,
kichThuocHinh: 'cover',
coXemTruoc: true
})
Hình minh họa bài viết
HinhAnh({
nguonHinh: hinhBaiViet,
rongHinh: '100%',
caoHinh: 250,
hinhDang: 'round',
banKinh: 12,
coXemTruoc: true,
hienThiChuThich: true,
noiDungChuThich: 'Mô tả hình'
})
Kết Luận
Tài liệu thực chiến này được biên soạn dựa trên kinh nghiệm dự án thực tế, bao gồm 6 kịch bản cốt lõi của thành phần RcImage trong HarmonyOS6, trình bày đầy đủ phương pháp sử dụng RcImage.