基礎元件
常用元件
- Text:顯示文字內容
- Image:顯示圖片
- Button:顯示一個按鈕
- Column: 縱向佈局
- Row:橫向佈局
- List:列表
各元件的用法
Text("文字元件")
.fontColor(Theme.Color.textPrimary)
.fontWeight(FontWeight.Medium)
.fontSize(20)
Image($r('app.media.banner'))
.objectFit(ImageFit.Fill)
.width('100%')
.height(100)
.opacity(191)
Button("按鈕").onClick((event) => {
//按鈕點選事件
})
Column() {
Text("文字1")
.fontColor(Theme.Color.textPrimary)
.fontWeight(FontWeight.Medium)
.fontSize(20)
Text("文字2")
.fontColor(Theme.Color.textPrimary)
.fontWeight(FontWeight.Medium)
.fontSize(20)
Text("文字3")
.fontColor(Theme.Color.textPrimary)
.fontWeight(FontWeight.Medium)
.fontSize(20)
}.width('100%')
Row() {
Text("文字1")
.fontColor(Theme.Color.textPrimary)
.fontWeight(FontWeight.Medium)
.fontSize(20)
Text("文字2")
.fontColor(Theme.Color.textPrimary)
.fontWeight(FontWeight.Medium)
.fontSize(20)
Text("文字3")
.fontColor(Theme.Color.textPrimary)
.fontWeight(FontWeight.Medium)
.fontSize(20)
}.width('100%')
List() {
ForEach(this.items, (item: string, index) => {
ListItem(){
Text(item).padding(10).width('100%')
}
})
}
Grid
用於展示網格列表
Grid(){
GridItem(){
Text("item1").padding(10)
}
GridItem(){
Text("item2").padding(10)
}
GridItem(){
Text("item12").padding(10)
}
}.columnsTemplate("1f 1f 1f") //列分佈規則
.rowsTemplate("1f 1f 1f") //行分佈規則
Grid的誇行/列設定
在建立Grid時可以傳入GridLayoutOptions來實現網格所佔行/列數
- regularSize,型別為[number,number],用來定義一般規則的Item所佔的行/列數
- irregularIndexes,型別為number[],用來指定不遵循一般規則的Item索引。
- onGetIrregularSizeByIndex,型別(index: number) => [number, number]的回撥函式,irregularIndexes中配置的索引會回撥到此函式,返回結果表示該Item所佔用的行/列數,[所佔行數,所佔列數]
@Preview
@Component
struct GridList {
item: Array<number> = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
layoutOption: GridLayoutOptions = {
regularSize: [1, 1], //一般規則的item佔用1行1列
irregularIndexes: [0, 5], //非一般規則item的索引
onGetIrregularSizeByIndex: (index: number) => {
if (index == 0) {
return [1, 2] //0索引處的item佔用1行2列
} else {
return [2, 1] //5索引處的item佔用2行1列
}
}
}
build() {
Grid(null, this.layoutOption) {
ForEach(this.item, (item: number, index) => {
GridItem() {
Stack() {
Text(item + "").textAlign(TextAlign.Center)
}.width('100%').height(index == 5 ? 105 : 50)
}.backgroundColor(Color.Pink)
}, (item: number, index) => {
return item + ""
})
}
.columnsTemplate('1fr 1fr')
.rowsGap(5)
.columnsGap(5)
.width('100%')
.height('100%')
}
}
WaterFlow
瀑布流
WaterFlow() {
FlowItem() {
Text("item1").padding(10)
}
FlowItem() {
Text("item2").padding(10)
}
}
瀑布流誇行/列設定
使用瀑布流的分組資訊(WaterFlowSections)可以設定item不同列數的混合佈局。
WaterFlowSections 中可以設定多個分組資訊,每個分組資訊包含如下內容:
● itemsCount 分組中的item數量
● crossCount 瀑布流的行/列數
● columnsGap/rowsGap:列/行間距
● margin 分組的外邊距
@Preview
@Component
struct WaterFlowListView {
items: Array<number> = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
@State sections: WaterFlowSections = new WaterFlowSections()
aboutToAppear(): void {
this.sections.push({
itemsCount: 1, //分組中的item數量
crossCount: 1, //分組中的列數
columnsGap: 8, //列間距
rowsGap: 8, //行間距
})
this.sections.push({
itemsCount: 8,
crossCount: 2,
columnsGap: 8,
rowsGap: 8,
margin:{
top: 8
}
})
this.sections.push({
itemsCount: 1,
crossCount: 1,
columnsGap: 8,
rowsGap: 8,
margin:{
top: 8
}
})
}
build() {
WaterFlow({ sections: this.sections }) {
ForEach(this.items, (item: number, index) => {
FlowItem() {
Stack() {
Text(item + "").textAlign(TextAlign.Center)
}.height(index*10 + 30)
}.backgroundColor(Color.Pink).width('100%')
}, (item: number, index) => {
return item + ""
})
}
.width('100%')
.height('100%')
}
}
頁面實現
準備資料
首先需要準備資料,包括詩詞內容,小知識,作者。
json檔案內容如下:
[
{
"title": "滿江紅·寫懷",
"dynasty": "南宋",
"author": "岳飛",
"introduction": "此詞上片寫作者悲憤中原重陷敵手,痛惜前功盡棄的局面,也表達自己繼續努力,爭取壯年立功的心願。\n此詞下片運轉筆端,抒寫詞人對於民族敵人的深仇大恨,統一祖國的殷切願望,忠於朝廷即忠於祖國的赤誠之心。",
"text": "怒髮衝冠,憑闌處、瀟瀟雨歇。\n抬望眼,仰天長嘯,壯懷激烈。\n三十功名塵與土,八千里路雲和月。\n莫等閒、白了少年頭,空悲切。\n靖康恥,猶未雪。\n臣子恨,何時滅。\n駕長車,踏破賀蘭山缺。\n壯志飢餐胡虜肉,笑談渴飲匈奴血。\n待從頭、收拾舊山河,朝天闕。",
"textAlign": "center",
"translation": "氣得頭髮豎起,以至於將帽子頂起,登高倚欄杆,一場瀟瀟細雨剛剛停歇。\n\n抬頭望眼四望遼闊一片,仰天長聲嘯嘆,一片報國之心充滿心懷。\n\n三十多年來雖已建立一些功名,但如同塵土微不足道,南北轉戰八千里,經過多少風雲人生。\n\n不要虛度年華,花白了少年黑髮,只有獨自悔恨悲悲切切。\n\n靖康年的奇恥,尚未洗雪。\n\n臣子憤恨,何時才能泯滅。\n\n我要駕著戰車向賀蘭山進攻,連賀蘭山也要踏為平地。\n\n我滿懷壯志,打仗餓了就吃敵人的肉,談笑渴了就喝敵人的鮮血。\n\n我要從頭再來,收復舊日河山,朝拜故都京闕。",
"searchKey": "manjianghong|mjh|mjhxh|song|yuefei|yf"
},
{
"title": "水調歌頭·明月幾時有",
"dynasty": "北宋",
"author": "蘇軾",
"introduction": "詞前的小序交待了寫詞的過程:“丙辰中秋,歡飲達旦,大醉。作此篇,兼懷子由。”蘇軾因為與當權的變法者王安石等人政見不同,自求外放,輾轉在各地為官。他曾經要求調任到離蘇轍較近的地方為官,以求兄弟多多聚會。公元1074年(熙寧七年)蘇軾差知密州。到密州後,這一願望仍無法實現。公元1076年的中秋,皓月當空,銀輝遍地,詞人與胞弟蘇轍分別之後,已七年未得團聚。此刻,詞人面對一輪明月,心潮起伏,於是乘酒興正酣,揮筆寫下了這首名篇。",
"text": "丙辰中秋,歡飲達旦,大醉,作此篇,兼懷子由。\n\n明月幾時有?把酒問青天。不知天上宮闕,今夕是何年。我欲乘風歸去,又恐瓊樓玉宇,高處不勝寒。起舞弄清影,何似在人間。\n\n轉朱閣,低綺戶,照無眠。不應有恨,何事長向別時圓?人有悲歡離合,月有陰晴圓缺,此事古難全。但願人長久,千里共嬋娟。",
"textAlign": "left",
"translation": "丙辰年的中秋節,高興地喝酒直到第二天早晨,喝到大醉,寫了這首詞,同時思念弟弟蘇轍。\n\n明月從什麼時候才開始出現的?我端起酒杯遙問蒼天。不知道在天上的宮殿,何年何月。我想要乘御清風回到天上,又恐怕在美玉砌成的樓宇,受不住高聳九天的寒冷。翩翩起舞玩賞著月下清影,哪像是在人間。\n\n月兒轉過硃紅色的樓閣,低低地掛在雕花的窗戶上,照著沒有睡意的自己。明月不該對人們有什麼怨恨吧,為什麼偏在人們離別時才圓呢?人有悲歡離合的變遷,月有陰晴圓缺的轉換,這種事自古來難以周全。只希望這世上所有人的親人能平安健康,即便相隔千里,也能共享這美好的月光。",
"rectify": {
"高觸不勝寒": "高觸不勝寒"
},
"searchKey": "shuidiaogetou|mingyuejishiyou|sdgt|myjsy|song|sushi|ss"
},
{
"title": "登高",
"dynasty": "唐",
"author": "杜甫",
"introduction": "此詩作於公元767年(唐代宗大曆二年)秋天,杜甫時在夔州。這是他在五十六歲時寫下的。一天他獨自登上夔州白帝城外的高臺,登高臨眺,蕭瑟的秋江景色,引發了他身世飄零的感慨,滲入了他老病孤愁的悲哀。於是,就有了這首被譽為“七律之冠”的《登高》。",
"text": "風急天高猿蕭哀,渚清沙白鳥飛回;\n無邊落木蕭蕭下,不盡長江滾滾來。\n萬里悲秋常作客,百年多病獨登臺;\n艱難苦恨繁霜鬢,潦倒新停濁酒杯。",
"textAlign": "center",
"translation": "風急天高猿猴啼叫顯得十分悲哀,水清沙白的河洲上有鳥兒在盤旋。\n無邊無際的樹木蕭蕭地飄下落葉,長江滾滾湧來奔騰不息。\n悲對秋景感慨萬里漂泊常年為客,一生當中疾病纏身今日獨上高臺。\n歷盡了艱難苦恨白髮長滿了雙鬢,衰頹滿心偏又暫停了澆愁的酒杯。",
"searchKey": "denggao|dg|tang|dufu|dg"
},
……
]
[
{
"title": "唐宋八大家",
"text": "唐宋八大家,又稱為“唐宋散文八大家”,是唐代和宋代八位散文家的合稱,分別為唐代韓愈、柳宗元和宋代歐陽修、蘇洵、蘇軾、蘇轍、王安石、曾鞏八位。\n其中韓愈、柳宗元是唐代古文運動的領袖,歐陽修、三蘇(蘇軾、蘇轍、蘇洵)等四人是宋代古文運動的核心人物,王安石、曾鞏是臨川文學的代表人物。他們先後掀起的古文革新浪潮,使詩文發展的陳舊面貌煥然一新。\n八大家中蘇家父子兄弟有三人,人稱“三蘇”,分別為蘇洵、蘇軾、蘇轍,又有“一門三學士”之譽。故可用“韓柳歐王曾三蘇”概括。"
},
{
"title": "醉八仙",
"text": "醉八仙,指唐朝嗜酒的八位學者名人,亦稱酒中八仙、飲中八仙。《新唐書·李白傳》載,李白、賀知章、李適之、汝陽王李璡、崔宗之、蘇晉、張旭、焦遂為“酒中八仙人”。杜甫有《飲中八仙歌》。瓷器畫面繪飲中八仙,每每於人物之上書以人名,以清朝為多見。\n一仙賀知章:知章騎馬似乘船,眼花落井水底眠。\n二仙汝陽王:汝陽三鬥始朝天,道逢麴車口流涎,恨不移封向酒泉。\n三仙李適之:左相日興費萬錢,飲如長鯨吸百川,銜杯樂聖稱避賢。\n四仙崔宗之:宗之瀟灑美少年,舉觴白眼望青天,皎如玉樹臨風前。\n五仙蘇晉:蘇晉長齋繡佛前,醉中往往愛逃禪。\n六仙李白:李白一斗詩百篇,長安市上酒家眠。天子呼來不上船,自稱臣是酒中仙。\n七仙張旭:張旭三杯草聖傳,脫帽露頂王公前,揮毫落紙如雲煙。\n八仙焦遂:焦遂五斗方卓然,高談雄辯驚四筵。"
},
……
]
[
{
"name": "蘇軾",
"dynasty": "北宋",
"introduction": "蘇軾(1037年—1101年),字子瞻,又字和仲,號鐵冠道人、東坡居士,世稱蘇東坡、蘇仙、坡仙。眉州眉山(今四川省眉山市)人,北宋文學家,書法家、畫家,歷史治水名人。與父蘇洵、弟蘇轍三人並稱“三蘇”。\n嘉祐二年(1057年),參加殿試中乙科,賜進士及第(一說賜進士出身)。嘉祐六年(1061年),參加制科考試,授大理評事、籤書鳳翔府判官。宋神宗時,曾在杭州、密州、徐州、湖州等地任職。元豐三年(1080年),因“烏臺詩案”,被貶為黃州團練副使。宋哲宗即位後,出任兵部尚書、禮部尚書等職,外放治理杭州、潁州、揚州、定州等地。隨著新黨執政,又被貶惠州、儋州。宋徽宗時,獲赦北還,病逝於常州。南宋時期,追贈太師,諡號“文忠”。\n蘇軾是北宋中期文壇領袖,在詩、詞、文、書、畫等方面取得很高成就。其詩題材廣闊,清新豪健,善用誇張比喻,獨具風格,與黃庭堅並稱“蘇黃”;其詞開豪放一派,與辛棄疾同是豪放派代表,並稱“蘇辛”;其文著述宏富,縱橫恣肆,豪放自如,與歐陽修並稱“歐蘇”,與韓愈、柳宗元、歐陽修、蘇洵、蘇轍、王安石、曾鞏合稱“唐宋八大家”;善書法,與黃庭堅、米芾、蔡襄合稱“宋四家”;擅長文人畫,尤擅墨竹、怪石、枯木等。作品有《東坡七集》《東坡易傳》《東坡樂府》《寒食帖》《瀟湘竹石圖》《枯木怪石圖》等。"
},
{
"name": "杜甫",
"dynasty": "唐",
"introduction": "杜甫(712年2月12日—770年),字子美,自號少陵野老,祖籍襄陽(今屬湖北),自其曾祖時遷居鞏縣(今河南鞏義西南)。唐代著名現實主義詩人。與李白合稱“李杜”“大李杜”,也常被稱為“老杜”。\n杜甫自幼好學,知識淵博,頗有政治抱負。唐玄宗開元后期,舉進士不第,漫遊各地。後寓居長安近十年,未能有所施展,生活貧困,逐漸對當時的社會狀況有較深的認識。後靠獻賦才得授小官。安史之亂爆發、長安失陷後,他曾被困城中半年,後逃至鳳翔,被唐肅宗拜為左拾遺,世稱“杜拾遺”。長安收復後,隨肅宗還京,又被外放為華州司功參軍。期間創作了《登高》《春望》《北征》以及“三吏”“三別”等名作。後棄官移家至成都,一度在劍南節度使嚴武幕中任參謀,被表授為檢校工部員外郎,故世稱“杜工部”。晚年攜家出蜀,於大曆五年(770年)冬在輾轉途中逝世,享年五十九歲。\n杜甫善於運用各種詩歌形式,尤長於律詩,風格多樣,而以沉鬱為主;語言精練,具有高度的表達能力。繼承和發展《詩經》以來注重反映社會現實的優良文學傳統,成為中國古代詩歌藝術發展的又一高峰,被後人公認為詩歌史上的“集大成者”。他的人格,也被認為是中華民族文人品格的楷模。自晚唐兩宋後,杜甫逐漸聲名遠播,對中國文學和日本文學都產生了深遠的影響。後世尊稱他為“詩聖”,稱其詩為“詩史” 。其傳世作品大多集於《杜工部集》。"
},
{
"name": "岳飛",
"dynasty": "南宋",
"introduction": "岳飛(1103年3月24日—1142年1月27日),字鵬舉,宋朝相州湯陰(今河南湯陰)人,祖籍東昌(今山東聊城),南宋時期抗金名將、軍事家、戰略家、民族英雄、書法家、詩人,位列南宋“中興四將”之首。\n岳飛從二十歲起,曾先後四次從軍。自建炎二年(1128年)遇宗澤至紹興十一年(1141年)止,先後參與、指揮大小戰鬥數百次。金軍攻打江南時,獨樹一幟,力主抗金,收復建康。紹興四年(1134年),收復襄陽六郡。紹興六年(1136年),率師北伐,順利攻取商州、虢州等地。紹興十年(1140年),完顏宗弼毀盟攻宋,岳飛揮師北伐,兩河人民奔走相告,各地義軍紛紛響應,夾擊金軍。岳家軍先後收復鄭州、洛陽等地,在郾城、潁昌大敗金軍,進軍朱仙鎮。宋高宗趙構和宰相秦檜卻一意求和,以十二道“金字牌”催令班師。在宋金議和過程中,岳飛遭受秦檜、張俊等人誣陷入獄。1142年1月,以莫須有的罪名,與長子岳雲、部將張憲一同遇害。宋孝宗時,平反昭雪,改葬於西湖畔棲霞嶺,追諡武穆,後又追諡忠武,封鄂王。 \n岳飛是南宋傑出的統帥,他重視人民抗金力量,締造了“連結河朔”之謀,主張黃河以北的民間抗金義軍和宋軍互相配合,以收復失地;治軍賞罰分明,紀律嚴整,又能體恤部屬,以身作則,率領的“岳家軍”號稱“凍死不拆屋,餓死不擄掠”。金軍有“撼山易,撼岳家軍難”的評語,以示對岳家軍的由衷敬佩。\n岳飛的文才同樣卓越,其代表詞作《滿江紅·怒髮衝冠》是千古傳誦的愛國名篇,後人輯有文集傳世。"
},
……
}
將json檔案放置在資源目錄 resources/rawfile/ 下載
使用時透過 import 匯入
import poetryList from 'resources/rawfile/poetry.json';
import tips from 'resources/rawfile/tips.json';
根據json資料格式定義資料實體類
export interface Poetry {
uuid?: string
title: string
dynasty: string
author: string
introduction: string
text: string
textAlign: string
translation: string
rectify?: object
searchKey: string
}
export class Tip {
uuid: string
title: string
text: string
}
首頁實現
首頁實現效果
首頁內容包括一個隨機的小知識和詩詞列表,因此我們可以使用List,Grid,WaterFlow元件來實現列表展示,這裡我們以WaterFlow為例。
小知識佈局
@Component
export struct TipView {
@Prop tip: Tip
viewHeight: number = 152
textFontSize: number = 19
textController: TextController = new TextController();
applyTextStyle() {
let style = TextStyleUtils.buildParagraphIndentStyle(this.tip.text, this.textFontSize * 2)
this.textController.setStyledString(style)
}
build() {
Stack({
alignContent: Alignment.TopStart
}) {
Image($r('app.media.tip_banner'))
.objectFit(ImageFit.Fill)
.width('100%')
.height(this.viewHeight)
.opacity(191)
Column() {
Text(this.tip.title)
.fontSize(20)
.fontWeight(FontWeight.Medium)
Text(undefined, { controller: this.textController })
.fontSize(this.textFontSize)
.lineHeight(26)
.maxLines(4)
.textOverflow({
overflow: TextOverflow.Ellipsis
})
.margin({ top: 5 })
.width("100%")
.onAppear(() => {
this.applyTextStyle()
})
}
.alignItems(HorizontalAlign.Start)
.padding({
top: 10,
bottom: 10,
left: 12,
right: 12
})
.width('100%')
.constraintSize({ maxHeight: this.viewHeight })
.backgroundColor(Theme.Color.tipShade)
}
.clip(true)
.borderRadius(10)
}
}
小知識內容涉及多個段落,為了閱讀方便,段落開始需要縮排2個漢字,HarmonyOS提供了 ParagraphStyle 類設定段落樣式。
export class TextStyleUtils {
static buildParagraphIndentStyle(text: string, offset: number): MutableStyledString {
let paragraphStyle: ParagraphStyle = new ParagraphStyle({ textIndent: LengthMetrics.vp(offset) });
let regArray = text.matchAll(/\n/g)
let styleArray: Array<StyleOptions> = []
styleArray.push({
start: 0,
length: 3,
styledKey: StyledStringKey.PARAGRAPH_STYLE,
styledValue: paragraphStyle
})
for (let match of regArray) {
styleArray.push({
start: match.index,
length: 3,
styledKey: StyledStringKey.PARAGRAPH_STYLE,
styledValue: paragraphStyle
})
}
return new MutableStyledString(text, styleArray)
}
}
詩詞列表項佈局
@Component
struct DataItemView {
@Prop item: Poetry
build() {
Column() {
Text(this.item.title)
.fontColor(Theme.Color.textPrimary)
.fontWeight(FontWeight.Medium)
.fontSize(20)
Text(`[${this.item.dynasty}]${this.item.author}`)
.fontColor(Theme.Color.textSecondary)
.fontSize(16)
.margin({ top: 2 })
Text(this.item.introduction)
.fontColor(Theme.Color.textSecondary)
.fontSize(16)
.margin({ top: 5 })
.maxLines(3)
.textOverflow({
overflow: TextOverflow.Ellipsis
})
}
.alignItems(HorizontalAlign.Start)
.padding(10)
}
}
瀑布流列表
列表第一項是小知識佈局,需要誇2列顯示,因此列表項分組如下:
- 小知識佈局,數量為1,展示1列
- 詩詞項佈局,數量為詩詞列表數量,展示2列
- 底部留白,數量為1,展示1列
@Component
struct WaterFlowView {
@Prop tip: Tip
@Prop poetryList: LazyDataSource<Poetry>
@State sections: WaterFlowSections = new WaterFlowSections()
aboutToAppear(): void {
this.sections.push({
itemsCount: 1,
crossCount: 1,
})
this.sections.push({
itemsCount: this.poetryList.totalCount(),
crossCount: 2,
columnsGap: 8,
rowsGap: 8,
})
this.sections.push({
itemsCount: 1,
crossCount: 1,
})
}
build() {
WaterFlow({ sections: this.sections, layoutMode: WaterFlowLayoutMode.SLIDING_WINDOW }) {
FlowItem() {
TipView({
tip: this.tip,
})
}
.padding({ top: 8, bottom: 8 })
.onClick(() => {
})
LazyForEach(this.poetryList,
(item: Poetry, index) => {
FlowItem() {
DataItemView({
item: item
})
}
.width('100%')
.borderRadius(10)
.backgroundColor(Theme.Color.inputEditTextBackground)
.onClick(() => {
})
},
(item: Poetry, index) => {
return item.uuid
}
)
FlowItem() {
Text().height(8).width('100%')
}
}
.width('100%')
.height('100%')
.padding({ left: 8, right: 8 })
}
詳情頁實現
詳情頁實現效果
詩詞正文部分可以根據內容居中或居左展示,【介紹】部分也是需要段落縮排(參考小知識佈局)。詳情頁佈局比較簡單,不在詳述。
本文的技術設計和實現都是基於作者工作中的經驗總結,如有錯誤,請留言指正,謝謝。