1、程序介紹
本案例使用TextArea實(shí)現(xiàn)多文本輸入,使用mediaLibrary實(shí)現(xiàn)在相冊(cè)中獲取圖片,使用image生成pixelMap,使用pixelMap的scale(),crop(),rotate()接口實(shí)現(xiàn)對(duì)圖片的縮放,裁剪,旋轉(zhuǎn)功能。
案例說(shuō)明:
發(fā)表評(píng)價(jià)頁(yè)面點(diǎn)擊添加圖片/照片,頁(yè)面跳轉(zhuǎn)到圖片選擇頁(yè)面。
進(jìn)入圖片選擇頁(yè)面后,選擇需要顯示的圖片,最多選擇6張圖片。
選中圖片后點(diǎn)擊下一步,頁(yè)面會(huì)跳轉(zhuǎn)到圖片編輯頁(yè)面,點(diǎn)擊縮放,頁(yè)面會(huì)顯示縮小,放大按鈕,點(diǎn)擊按鈕,可對(duì)圖片進(jìn)行縮小,放大操作。點(diǎn)擊裁剪,頁(yè)面會(huì)跳出裁剪比例,點(diǎn)擊想要裁剪的比例可以對(duì)圖片進(jìn)行裁剪。點(diǎn)擊旋轉(zhuǎn)可對(duì)圖片進(jìn)行旋轉(zhuǎn)。
圖片編輯完成后,點(diǎn)擊確認(rèn),頁(yè)面會(huì)跳轉(zhuǎn)到發(fā)表評(píng)價(jià)頁(yè)面,顯示相關(guān)照片。點(diǎn)擊添加圖片/照片可以對(duì)圖片進(jìn)行重新選擇。
點(diǎn)擊返回按鈕,退出應(yīng)用。
API接口:9
2、知識(shí)準(zhǔn)備
2.1、TextArea
多行文本輸入框組件,當(dāng)輸入的文本內(nèi)容超過(guò)組件寬度時(shí)會(huì)自動(dòng)換行顯示。
function TextArea(value?:{placeholder?: ResourceStr, text?: ResourceStr, controller?: TextAreaController})
其中,參數(shù)定義如下:
參數(shù)名 | 參數(shù)類型 | 必填 | 參數(shù)描述 |
---|---|---|---|
placeholder | ResourceStr | 否 | 設(shè)置無(wú)輸入時(shí)的提示文本 |
text | ResourceStr | 否 | 設(shè)置輸入框當(dāng)前的文本內(nèi)容 |
controller | TextAreaController | 否 | 設(shè)置TextArea控制器 |
其中,屬性可支持如下:
名稱 | 參數(shù)類型 | 描述 |
---|---|---|
placeholderColor | ResourceColor | 設(shè)置placeholder文本顏色 |
placeholderFont | Font | 設(shè)置plaoceholder文本樣式 |
textAlign | TextAlign | 設(shè)置文本在輸入框中的水平對(duì)齊式默認(rèn)值:TextAlign.Start |
caretColor | ResourceColor | 設(shè)置輸入框光標(biāo)顏色 |
inputFilter | {value: ResourceStr,error?: (value: string) => void} | 通過(guò)正則表達(dá)式設(shè)置輸入過(guò)濾器。匹配表達(dá)式的輸入允許顯示,不匹配的輸入將被過(guò)濾。僅支持單個(gè)字符匹配,不支持字符串匹配。- value:設(shè)置正則表達(dá)式。- error:正則匹配失敗時(shí),返回被過(guò)濾的內(nèi)容。 |
copyOption | CopyOptions | 設(shè)置輸入的文本是否可復(fù)制。設(shè)置CopyOptions.None時(shí),當(dāng)前TextArea中的文字無(wú)法被復(fù)制或剪切,僅支持粘貼。 |
2.2、mediaquery
ohos.mediaquery提供媒體查詢,提供根據(jù)不同媒體類型定義不同的樣式。
2.2.1、導(dǎo)入模塊
import mediaquery from '@ohos.mediaquery'
2.2.2、 mediaquery.matchMediaSync
function matchMediaSync(condition: string): MediaQueryListener
設(shè)置媒體查詢的查詢條件,并返回對(duì)應(yīng)的監(jiān)聽(tīng)句柄。
參數(shù)定義如下所示:
參數(shù)名 | 類型 | 必填 | 說(shuō)明 |
---|---|---|---|
condition | string | 是 | 媒體事件的匹配事件 |
返回值定義如下所示:
類型 | 說(shuō)明 |
---|---|
MediaQueryListener | 媒體事件監(jiān)聽(tīng)句柄,用于注冊(cè)和銷毀監(jiān)聽(tīng)回調(diào) |
2.2.3、MediaQueryListener
媒體查詢的句柄,并包含了申請(qǐng)句柄時(shí)的首次查詢結(jié)果。
系統(tǒng)能力:SystemCapability.ArkUI.ArkUI.Full
(1)屬性
名稱 | 類型 | 可讀 | 可寫(xiě) | 說(shuō)明 |
---|---|---|---|---|
matches | boolean | 是 | 否 | 是否符合匹配條件 |
media | string | 是 | 否 | 媒體事件的匹配條件 |
(2)on函數(shù)
function on(type: 'change', callback: Callback<MediaQueryResult>): void
通過(guò)句柄向?qū)?yīng)的查詢條件注冊(cè)回調(diào),當(dāng)媒體屬性發(fā)生變更時(shí)會(huì)觸發(fā)該回調(diào)。
系統(tǒng)能力:SystemCapability.ArkUI.ArkUI.Full
參數(shù):
參數(shù)名 | 類型 | 必填 | 說(shuō)明 |
---|---|---|---|
type | string | 是 | 必須填寫(xiě)字符串change |
callback | Callback | 是 | 向媒體查詢注冊(cè)的回調(diào) |
(3)off函數(shù)
function off(type: 'change', callback?: Callback<MediaQueryResult>): void
通過(guò)句柄向?qū)?yīng)的查詢條件去注冊(cè)回調(diào),當(dāng)媒體屬性發(fā)生變更時(shí)不在觸發(fā)指定的回調(diào)。
系統(tǒng)能力:SystemCapability.ArkUI.ArkUI.Full
參數(shù):
參數(shù)名 | 類型 | 必填 | 說(shuō)明 |
---|---|---|---|
type | string | 是 | 必須填寫(xiě)字符串change |
callback | Callback | 否 | 需要去注冊(cè)的回調(diào),如果參數(shù)缺省則去注冊(cè)該句柄下所有的回調(diào) |
2.2.4、MediaQueryResult
用于執(zhí)行媒體查詢操作。
系統(tǒng)能力:SystemCapability.ArkUI.ArkUI.Full
(1)屬性
名稱 | 類型 | 可讀 | 可寫(xiě) | 說(shuō)明 |
---|---|---|---|---|
matches | boolean | 是 | 否 | 是否符合匹配條件 |
media | string | 是 | 否 | 媒體事件的匹配條件 |
2.3、mediaLibrary
MediaLibrary支持能力列舉如下:
查詢圖片和視頻相冊(cè)
媒體文件操作如創(chuàng)建、重命名、拷貝和刪除
相冊(cè)操作如創(chuàng)建、重命名和刪除
MediaLibrary整體框架,如下所示:
詳細(xì)請(qǐng)參考:官方文檔
2.4、Grid
網(wǎng)格容器,由“行”和“列”分割的單元格所組成,通過(guò)指定“項(xiàng)目”所在的單元格做出各種各樣的布局。
詳細(xì)請(qǐng)參考:官方文檔
2.5、@ohos.multimedia.image
本模塊提供圖片處理效果,包括通過(guò)屬性創(chuàng)建PixelMap、讀取圖像像素?cái)?shù)據(jù)、讀取區(qū)域內(nèi)的圖片數(shù)據(jù)等。
詳細(xì)請(qǐng)參考:官方文檔
2.6、@ohos.router
本模塊提供通過(guò)不同的url訪問(wèn)不同的頁(yè)面,包括跳轉(zhuǎn)到應(yīng)用內(nèi)的指定頁(yè)面、用應(yīng)用內(nèi)的某個(gè)頁(yè)面替換當(dāng)前頁(yè)面、返回上一頁(yè)面或指定的頁(yè)面等。
詳細(xì)請(qǐng)參考:官方文檔
3、程序解析
3.1、申請(qǐng)?jiān)O(shè)備權(quán)限
配置文件module.json5中聲明權(quán)限,申請(qǐng)應(yīng)用讀取、寫(xiě)入用戶外部存儲(chǔ)中的媒體文件信息以及允許應(yīng)用訪問(wèn)用戶媒體文件中的地理位置信息。
"requestPermissions": [ { "name": "ohos.permission.READ_MEDIA", "reason": "$string:media_read_permission", "usedScene": { "abilities": [ "MainAbility" ], "when": "inuse" } }, { "name": "ohos.permission.WRITE_MEDIA", "reason": "$string:media_write_permission", "usedScene": { "abilities": [ "MainAbility" ], "when": "inuse" } }, { "name": "ohos.permission.MEDIA_LOCATION", "reason": "$string:media_location_permission", "usedScene": { "abilities": [ "MainAbility" ], "when": "inuse" } }]
3.2、Index.ets
首先,聲明1個(gè)pixelMaps數(shù)組,用于存放照片或視頻。
@StorageLink('pixelMaps') pixelMaps: Array<image.PixelMap> = []
注意:@StorageLink('pixelMaps')表明通過(guò)使用@StorageLink(key)裝飾的狀態(tài)變量,與AppStorage建立雙向數(shù)據(jù)綁定。
其次,在build()調(diào)用之前運(yùn)行aboutToAppear(),負(fù)責(zé)獲取AppStorage的pixelMaps屬性,然后往當(dāng)前頁(yè)傳入isShowCamera參數(shù)。
aboutToAppear() {
logger.info(TAG, 'enter aboutToAppear')
// 與AppStorage建立雙向數(shù)據(jù)綁定,獲取pixelMaps屬性
if (AppStorage.Get('pixelMaps')) {
this.pixelMaps.push(undefined)
}
// 獲取發(fā)起跳轉(zhuǎn)的頁(yè)面往當(dāng)前頁(yè)傳入的參數(shù)
if (router.getParams() && router.getParams()['isShowCamera']) {
this.isShowCamera = true
}
}
最后,build()顯示整個(gè)頁(yè)面。
其中,已選圖片通過(guò)Grid和GridItem控件排列顯示。
// 使用網(wǎng)格容器將已選照片顯示出現(xiàn)
Grid() {
// 輪流顯示成1行照片
ForEach(this.pixelMaps, (item, index) => {
GridItem() {
if (index < this.pixelMaps.length - 1) {
Image(item)
.width('100%')
.height(100)
.borderRadius(10)
} else {
// 最后一個(gè)為"添加圖片/照片"
Column() {
Image($r('app.media.photo'))
.height(40)
.width(40)
.onClick(() => {
router.push({
url: 'pages/ChoicePhotos'
})
})
Text($r('app.string.add_picture'))
.fontSize(13)
}
.alignItems(HorizontalAlign.Center)
.justifyContent(FlexAlign.Center)
.width('100%')
.height(100)
.borderRadius(10)
.backgroundColor('#F1F3F5')
}
}
})
}
.columnsTemplate('1fr 1fr 1fr 1fr')
.columnsGap(8)
.rowsGap(8)
.margin({ top: 8 })
.width('94%')
.height(105 * (this.pixelMaps.length > 4 ? 2 : 1))
3.3、ChoicePhotos.ets
該頁(yè)面為選擇照片頁(yè)面。該頁(yè)面通過(guò)調(diào)用ChoicePhoto()顯示頁(yè)面。
@Entry @Component struct ChoicePhotos {
build() {
Column() {
ChoicePhoto()
}
}
}
ChoicePhoto()主要負(fù)責(zé)顯示照片視頻以及添加等功能的界面。
首先,聲明1個(gè)MediaLibrary類對(duì)象和監(jiān)聽(tīng)句柄listener,用于查詢音頻、視頻和圖片文件元數(shù)據(jù)信息。
private mediaLibraryInstance: mediaLibrary.MediaLibrary = mediaLibrary.getMediaLibrary(getContext(this) as any)
private listener = mediaQuery.matchMediaSync('screen and (min-aspect-ratio: 1.5) or (orientation: landscape)')
其次,調(diào)用build()之前做初始化工作,主要是開(kāi)啟監(jiān)聽(tīng)句柄listener的change事件,并獲取設(shè)備端保存的圖片資源。
async aboutToAppear() { logger.info(TAG, `aboutToAppear`) this.listener.on('change', this.onLand) this.nextText = await this.convertResourceToString($r('app.string.next')) // 獲取圖片的文件信息 this.getFileAssetsFromType(mediaLibrary.MediaType.IMAGE)}
其中,getFileAssetsFromType()獲取設(shè)備端所有的圖片或視頻的文件信息。
async getFileAssetsFromType(mediaType: mediaLibrary.MediaType) { logger.info(TAG, `getFileAssetsFromType`) let context = getContext(this) as any // 獲取媒體庫(kù)的實(shí)例,用于訪問(wèn)和修改用戶等個(gè)人媒體數(shù)據(jù)信息(如音頻、視頻、圖片、文檔等) let mediaLibraryInstance = mediaLibrary.getMediaLibrary(context) if (!mediaLibraryInstance) { return } logger.info(TAG, `mediaLibraryInstance = ${JSON.stringify(mediaLibraryInstance)}`) // 創(chuàng)建文件獲取選項(xiàng),此處參數(shù)為獲取image類型的文件資源 let fileKeyObj = mediaLibrary.FileKey let fetchOp = { selections: `${fileKeyObj.MEDIA_TYPE}=?`, selectionArgs: [`${mediaType}`], } // 獲取文件資源 let fetchFileResult = await mediaLibraryInstance.getFileAssets(fetchOp) logger.info(TAG, `fetchFileResult = ${JSON.stringify(fetchFileResult)} , ${fetchFileResult.getCount()}`) if (fetchFileResult && fetchFileResult.getCount() > 0) { this.medias = await fetchFileResult.getAllObject() } logger.info(TAG, `this.medias = ${JSON.stringify(this.medias)}`)}
再次,使用Grid和GridItem控件顯示圖片或視頻。
Grid() { ForEach(this.medias, (item, index) => { GridItem() { Stack({ alignContent: Alignment.TopEnd }) { Image(item.uri) .width('100%') .height('100%') .borderRadius(10) .objectFit(ImageFit.Fill)
if (this.isShowChoices[index]) { this.showChoiceBuild('#e92f4f', this.choiceMedias.indexOf(item) + 1) } else { this.showChoiceBuild('#ffb7b4b4', 0) } } .width('100%') .height('100%') .onClick(() => { this.isShowChoices[index] = !this.isShowChoices[index] if (this.isShowChoices[index]) { if (this.choiceMedias.length > 5) { prompt.showDialog({ message: $r('app.string.choice_number') }) this.isShowChoices[index] = !this.isShowChoices[index] return } this.choiceMedias.push(item) } else { if (this.choiceMedias.indexOf(item) != -1) { this.choiceMedias.splice(this.choiceMedias.indexOf(item), 1) } } }) } .aspectRatio(1) })}
最后,定義1個(gè)按鍵事件。一旦選中某個(gè)圖片,可進(jìn)入圖片編輯頁(yè)面。
Button(`${this.nextText} ${this.isChoice === true ? `(${this.choiceMedias.length})` : ''}`) .fontSize(20) .height(32) .backgroundColor(this.isChoice === true ? '#E92F4F' : '#fffa8e8e') .margin({ right: 10 }) .borderRadius(20) .onClick(() => { if (this.isChoice === false) { return } this.mediaUris = this.choiceMedias.map((item) => { return item.uri }) // 跳轉(zhuǎn)到圖片編輯頁(yè)面 router.push({ url: 'pages/EditPages', params: { mediaUris: this.mediaUris, isLand: this.isLand } }) })
4、項(xiàng)目編譯
4.1、打開(kāi)項(xiàng)目
打開(kāi)DevEco Studio,再打開(kāi)自定義通知項(xiàng)目。
4.2、編譯程序
點(diǎn)擊菜單欄上的“Build” -> "Rebuild Project"。如果出現(xiàn)無(wú)法編譯,則注意查看Event Log界面。如下所示:
點(diǎn)擊Run 'npm install',讓DevEco Studio安裝相關(guān)依賴包。
重新點(diǎn)擊菜單欄上的“Build” -> "Rebuild Project"。出現(xiàn)如下錯(cuò)誤:
點(diǎn)擊上圖紅色框部分,安裝相關(guān)服務(wù)。
重新點(diǎn)擊菜單欄上的“Build” -> "Rebuild Project",編譯成功。
4.3、安裝程序
點(diǎn)擊“entry”按鈕,將項(xiàng)目程序安裝到設(shè)備端。如下圖所示:
如果出現(xiàn)下述報(bào)錯(cuò),表示無(wú)法安裝。如圖所示:
點(diǎn)擊上圖紅色框的藍(lán)色字體,彈出"Project Structure"對(duì)話框,點(diǎn)擊"Apply",再點(diǎn)擊"OK"。如圖所示:
重新點(diǎn)擊“entry”按鈕,將項(xiàng)目程序安裝到設(shè)備端。
5、運(yùn)行結(jié)果
-
APP
+關(guān)注
關(guān)注
33文章
1573瀏覽量
72439 -
應(yīng)用開(kāi)發(fā)
+關(guān)注
關(guān)注
0文章
58瀏覽量
9357 -
OpenHarmony
+關(guān)注
關(guān)注
25文章
3713瀏覽量
16254
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論