GridRow/GridCol(柵格布局)
GridRow/GridCol(柵格布局)是響應(yīng)式布局的一種,響應(yīng)式布局可以實(shí)現(xiàn)界面隨外部容器尺寸分級不連續(xù)變化而變化。
所以GridRow/GridCol(柵格布局)的適用場景:隨尺寸變化組件結(jié)構(gòu)不同的場景,比如:外部容器大小發(fā)生變化時,組件元素可以根據(jù)斷點(diǎn)、柵格或特定的特征(如橫豎屏方向切換、窗口寬高變化,不同設(shè)備的尺寸等)自動變化以適應(yīng)外部容器變化的布局能力
GridRow:柵格容器組件,需與結(jié)合其子組件GridCol開發(fā),可以適配不同尺寸的設(shè)備,讓各個設(shè)備可以合理的顯示,以此亦完成不同屏幕尺寸的UI適配。
一、GridRow參數(shù):breakpoints、columns和gutter(文章里會詳細(xì)說明)
斷點(diǎn):breakpoint
官方:柵格系統(tǒng)以設(shè)備的水平寬度(屏幕密度像素值,單位vp)作為斷點(diǎn)依據(jù),定義設(shè)備的寬度類型,形成了一套斷點(diǎn)規(guī)則。開發(fā)者可根據(jù)需求在不同的斷點(diǎn)區(qū)間實(shí)現(xiàn)不同的頁面布局效果。
為了便于理解,通過下面的示例代碼進(jìn)行說明。閱覽示例代碼可知,brerakpoints是GridRow的參數(shù)。value(數(shù)組)和reference(枚舉值)是breakpoints的兩個成員變量。
示例代碼:breakpoints: {?
value: ['300vp','600vp','800vp','1000vp','1200vp'],
?reference:BreakpointsReference.WindowSize
?}
1、WindowSize:reference的默認(rèn)值為BreakpointsReference.WindowSize,此值表示是以設(shè)備的寬度作為參照,通過屏寬與value內(nèi)的每個元素進(jìn)行比較。跟設(shè)備有關(guān),因為不同設(shè)備,屏寬可能不同。
屏寬屬于[0, 300vp)就是xs,表示最小寬度類型設(shè)備。(屏寬 < 300)
屏寬屬于[300, 600vp)就是sm,表示小寬度類型設(shè)備。(屏寬 >= 300 && 屏寬 < 600)
屏寬屬于[600, 800vp)就是md,表示中等寬度類型設(shè)備。
屏寬屬于[800, 1000vp)就lg,表示大寬度類型設(shè)備。
屏寬屬于[1000, 1200vp)就是xl,表示特大寬度類型設(shè)備。
屏寬屬于[1200, +∞)就是xxl,表示超大寬度類型設(shè)備。
2、ComponentSize:若reference的值為BreakpointsReference.ComponentSize,表示是以容器(GridRow)的尺寸作為參照,通過容器的width與value內(nèi)的每個元素進(jìn)行比較,比較原理與屏寬一致。
需要注意:因為此時是用容器的尺寸的進(jìn)行比較,所以與當(dāng)前的設(shè)備就無關(guān)了(若按設(shè)備百分比設(shè)置寬度,那跟屏寬還是有關(guān)系的)。
重點(diǎn)說明:在示例代碼中,values =??['300vp', '600vp', '800vp', '1000vp', '1200vp'],但values中元素的值是不固定的,理論上只要從小到大排列即可,但這需要跟當(dāng)前的需求做出相應(yīng)的調(diào)整,因為官方要求最多只能有xs、sm、md、lg、xl、xxl六個斷點(diǎn),所以value中最多只能有五個元素,若只有四個元素,則xxl自動失效,可省去,以此類推,若里面只有一個元素,那就意味著所有情況都只有xs[0, '300vp')和sm['300vp', +∞)兩個斷點(diǎn)。
span中的xs等斷點(diǎn)所傳入的值是所占列數(shù),不理解可以暫時先跳過,下面會詳細(xì)講解
@Entry
@Component
struct Index {
? @State gridRowWidth: number = 200;
? colors: Color[] = [Color.Red, Color.Yellow, Color.Pink, Color.Orange, Color.Brown, Color.Blue, Color.Orange, Color.Gray]
? build() {
? ? Column() {
? ? ? GridRow({
? ? ? ? breakpoints: {
? ? ? ? ? value: ['300vp', '600vp', '800vp', '1000vp', '1200vp'],
? ? ? ? ? // reference: BreakpointsReference.WindowSize, // 以設(shè)備尺寸作為參照,跟設(shè)備有關(guān)
? ? ? ? ? reference: BreakpointsReference.ComponentSize // 以容器組件尺寸作為參照,絕對尺寸,此處與設(shè)備無關(guān)
? ? ? ? },
? ? ? ? direction: GridRowDirection.Row // 排列方式:從左至右
? ? ? }) {
? ? ? ? ForEach(this.colors, (item: Color, index: Number) => {
? ? ? ? ? GridCol({
? ? ? ? ? ? span: {
? ? ? ? ? ? ? xs: 12, //設(shè)備/容器組件寬度在【0, 300) 之間,即為xs。 在最小寬度類型設(shè)備上,GridCol占據(jù)的GridRow中的12列。
? ? ? ? ? ? ? sm: 6, // 設(shè)備/容器組件寬度在【300, 600) 之間,即為sm。在小寬度類型設(shè)備上,GridCol占據(jù)的GridRow中的6列。
? ? ? ? ? ? ? md: 4, // 設(shè)備/容器組件寬度在【600, 800) 之間,即為md。在中等寬度類型設(shè)備上,GridCol占據(jù)的GridRow中的4列。
? ? ? ? ? ? ? lg: 3, // 設(shè)備/容器組件寬度在【800, 1000) 之間,即為lg。在大寬度類型設(shè)備上,GridCol占據(jù)的GridRow中的3列。
? ? ? ? ? ? ? xl: 2, // 設(shè)備/容器組件寬度在【1000, 1300) 之間,即為xl。在特大寬度類型設(shè)備上,GridCol占據(jù)的GridRow中的2列。
? ? ? ? ? ? ? xxl: 1 // 設(shè)備/容器組件寬度在【1200, +∞)之間,即為xxl。在超大寬度類型設(shè)備上,GridCol占據(jù)的GridRow中的1列。
? ? ? ? ? ? }
? ? ? ? ? }) {
? ? ? ? ? ? Row() {
? ? ? ? ? ? ? Text(index.toString())
? ? ? ? ? ? ? ? .fontSize(20)
? ? ? ? ? ? ? ? .fontWeight(FontWeight.Bold)
? ? ? ? ? ? ? ? .width('100%')
? ? ? ? ? ? ? ? .textAlign(TextAlign.Center)
? ? ? ? ? ? ? ? .onClick(() => {
? ? ? ? ? ? ? ? ? this.gridRowWidth += 50; //修改容器組件GridRow的寬度,用于測試,前提:以容器組件為參照
? ? ? ? ? ? ? ? })
? ? ? ? ? ? }.width('100%').height(50)
? ? ? ? ? }
? ? ? ? ? .backgroundColor(item)
? ? ? ? }, (item: Color) => item.toString())
? ? ? }
? ? ? .width(`${this.gridRowWidth}vp`)
? ? ? .height(500)
? ? ? .backgroundColor('#f5f5f5')
? ? }
? ? .width('100%')
? }
}

columns
columns默認(rèn)值是12,即在不設(shè)此參數(shù)時,默認(rèn)12列,也可以自定義
同樣通過下面示例代碼進(jìn)行說明:
1、columns是一個復(fù)合值類型(number |?GridRowColumnOption)。
當(dāng)columns為number類型時,比如columns: 10,在任何情況下GridRow都被分為10列。下面分別設(shè)置GridRow列數(shù)為6和10,子元素分別占2列和5列,下面代碼就是columns為number類型的示例代碼。
當(dāng)columns類型為GridRowColumnOption時,比如columns: { sm: 4, md: 8 },表示在斷點(diǎn)為sm時,GridRow被分為4列;點(diǎn)斷為md時,GridRow被分為8列,其他情況默認(rèn)還是12列。GridRowColumnOption的代碼就不做演示了,原理大同小異。
gutter
gutter也是一個復(fù)合值類型(Length | GutterOption)。
當(dāng)gutter為Length類型時,例如:gutter: 20,表示GridCol之間的距離上下左右的距離均為20。
也可以為GutterOption類型,例如:gutter: {x:20, y: 10},表示水平方向間距20,垂直方向間距10。
備注:當(dāng)一行展示不下時,自動折行。
代碼與效果圖如下:
@Entry
@Component
struct Index {
? colors: Color[] = [
? ? Color.Red, Color.Yellow, Color.Pink, Color.Orange,
? ? Color.Brown, Color.Blue, Color.Yellow, Color.Orange,
? ? Color.Gray, Color.Pink, Color.Orange, Color.Brown];
? build() {
? ? Column({space: 30}) {
? ? ? GridRow({
? ? ? ? gutter: 20, // GridCol之間的間距為20,也可以設(shè)置為{x:20, y: 10},表示水平方向間距20,垂直方向間距10
? ? ? ? columns: 6 // 表示一共把GridRow的寬度分為6列(為了更好理解,可以理解成分為了6份)
? ? ? }) {
? ? ? ? ForEach(this.colors, (item: Color, index: Number) => {
? ? ? ? ? GridCol({
? ? ? ? ? ? span: 2 // 共6份,此設(shè)置表示占2份的寬度, 所以會展示3列
? ? ? ? ? }) {
? ? ? ? ? ? Row() {
? ? ? ? ? ? ? Text(index.toString())
? ? ? ? ? ? ? ? .fontSize(20)
? ? ? ? ? ? ? ? .fontWeight(FontWeight.Bold)
? ? ? ? ? ? ? ? .width('100%')
? ? ? ? ? ? ? ? .textAlign(TextAlign.Center)
? ? ? ? ? ? }.width('100%').height(50)
? ? ? ? ? }
? ? ? ? ? .backgroundColor(item)
? ? ? ? }, (item: Color) => item.toString())
? ? ? }
? ? ? .width('100%')
? ? ? .height(500)
? ? ? .backgroundColor('#f5f5f5')
? ? ? GridRow({
? ? ? ? gutter: {x: 20, y: 10}, // 表示為{x:20, y: 10},表示水平方向間距20,垂直方向間距10
? ? ? ? columns: 10 // 10列
? ? ? }){
? ? ? ? ForEach(this.colors, (item: Color, index: number) => {
? ? ? ? ? GridCol({
? ? ? ? ? ? span: 5 // 共10份,此設(shè)置表示占5份的寬度, 所以會展示2列
? ? ? ? ? }) {
? ? ? ? ? ? Row(){
? ? ? ? ? ? ? Text(index.toString())
? ? ? ? ? ? ? ? .fontSize(20)
? ? ? ? ? ? ? ? .fontWeight(FontWeight.Bold)
? ? ? ? ? ? ? ? .width('100%')
? ? ? ? ? ? ? ? .textAlign(TextAlign.Center)
? ? ? ? ? ? }
? ? ? ? ? ? .backgroundColor(item)
? ? ? ? ? ? .width('100%')
? ? ? ? ? ? .height(50)
? ? ? ? ? }
? ? ? ? }, (item: Color) => item.toString())
? ? ? }
? ? ? .width('100%')
? ? ? .height(500)
? ? ? .backgroundColor('#f5f5f5')
? ? }
? ? .width('100%')
? }
}

3、columns默認(rèn)值為12,沒傳入columns時,柵格布局被分成12列,與斷點(diǎn)無關(guān)了,如下代碼與效果圖如下:
@Entry
@Component
struct Index {
? colors: Color[] = [
? ? Color.Red, Color.Yellow, Color.Pink, Color.Orange,
? ? Color.Brown, Color.Blue, Color.Yellow, Color.Orange,
? ? Color.Gray, Color.Pink, Color.Orange, Color.Brown];
? build() {
? ? Column() {
? ? ? GridRow() {
? ? ? ? ForEach(this.colors, (item: Color, index: Number) => {
? ? ? ? ? GridCol() {
? ? ? ? ? ? Row() {
? ? ? ? ? ? ? Text(index.toString())
? ? ? ? ? ? ? ? .fontSize(20)
? ? ? ? ? ? ? ? .fontWeight(FontWeight.Bold)
? ? ? ? ? ? ? ? .width('100%')
? ? ? ? ? ? ? ? .textAlign(TextAlign.Center)
? ? ? ? ? ? }.width('100%').height(50)
? ? ? ? ? }
? ? ? ? ? .backgroundColor(item)
? ? ? ? }, (item: Color) => item.toString())
? ? ? }
? ? ? .width('100%')
? ? ? .height(500)
? ? ? .backgroundColor('#f5f5f5')
? ? }
? ? .width('100%')
? }
}

三、子組件GridCol的參數(shù):span、offset、order
1、span
也是一個復(fù)合值類型 (number | GridColColumnOption)。
當(dāng)span為number類型時,比如span: 4,表示所有情況GridCol都占4列。
當(dāng)span為GridColColumnOption類型時,如第一份代碼中,span{xs: 12}, 表示在對應(yīng)為xs斷點(diǎn)時,當(dāng)前的GridCol占12列。
2、offset
也是一個復(fù)合值類型 (number | GridColColumnOption),表示GridCol相對于前一個GridCol的偏移列數(shù),默認(rèn)為0。
當(dāng)類型為number時,GridCol偏移相同列數(shù)。例如:offset: 2,偏移量為2列
當(dāng)類型為GridColColumnOption時,例如:offset: { xs: 1, sm: 2, md: 3, lg: 4 },邏輯與span類型,分?jǐn)帱c(diǎn)情況設(shè)置的偏移量
當(dāng)一行的最后偏移量不夠時,需要換行繼續(xù)偏移
3、order
也是一個復(fù)合值類型 (number |?GridColColumnOption),表示GridCol當(dāng)前的排序編號,定GridCol排列次序。當(dāng)GridCol不設(shè)置order或者設(shè)置相同的order, GridCol按照代碼順序展示。GridCol排序是按order從小到大的排列。未設(shè)置order的GridCol依次排序靠前,設(shè)置了order的GridCol按照數(shù)值從小到大排列。
當(dāng)類型為number時。例如:order: 2,表示序號為2
當(dāng)類型為GridColColumnOption時,例如:offset: { xs: 1, sm: 2, md: 3, lg: 4 },邏輯與span類型,分?jǐn)帱c(diǎn)情況設(shè)置的序號
示例代碼和效果圖如下:
@Entry
@Component
struct Index {
? colors: Color[] = [
? ? Color.Red, Color.Yellow, Color.Pink, Color.Orange,
? ? Color.Brown, Color.Blue, Color.Yellow, Color.Orange,
? ? Color.Gray, Color.Pink, Color.Orange, Color.Brown];
? build() {
? ? Column({ space: 30 }) {
? ? ? GridRow({
? ? ? ? columns: 10 // 表示一共把GridRow的寬度分為10列
? ? ? }) {
? ? ? ? ForEach(this.colors, (item: Color, index: Number) => {
? ? ? ? ? GridCol({
? ? ? ? ? ? span: 2 // 共10份,此設(shè)置表示占2份的寬度, 所以會展示5列
? ? ? ? ? }) {
? ? ? ? ? ? Row() {
? ? ? ? ? ? ? Text(index.toString())
? ? ? ? ? ? ? ? .fontSize(20)
? ? ? ? ? ? ? ? .fontWeight(FontWeight.Bold)
? ? ? ? ? ? ? ? .width('100%')
? ? ? ? ? ? ? ? .textAlign(TextAlign.Center)
? ? ? ? ? ? }.width('100%').height(50)
? ? ? ? ? }
? ? ? ? ? .backgroundColor(item)
? ? ? ? }, (item: Color) => item.toString())
? ? ? }
? ? ? .width('100%')
? ? ? .height(500)
? ? ? .backgroundColor('#f5f5f5')
? ? ? GridRow({
? ? ? ? columns: 10 // 10列
? ? ? }) {
? ? ? ? ForEach(this.colors, (item: Color, index: number) => {
? ? ? ? ? GridCol({
? ? ? ? ? ? span: 2,
? ? ? ? ? ? offset: 2 // 子組件偏移相同列數(shù)2,當(dāng)一行的最后偏移量不夠時,需要換行繼續(xù)偏移。注意:此處偏移不是指行首子組件偏移,而是所有子組件都會偏移
? ? ? ? ? ? // offset: {xs: 2, sm: 3} // 與span屬性類似,也支持分?jǐn)帱c(diǎn)傳值
? ? ? ? ? }) {
? ? ? ? ? ? Row() {
? ? ? ? ? ? ? Text(index.toString())
? ? ? ? ? ? ? ? .fontSize(20)
? ? ? ? ? ? ? ? .fontWeight(FontWeight.Bold)
? ? ? ? ? ? ? ? .width('100%')
? ? ? ? ? ? ? ? .textAlign(TextAlign.Center)
? ? ? ? ? ? }
? ? ? ? ? ? .backgroundColor(item)
? ? ? ? ? ? .width('100%')
? ? ? ? ? ? .height(50)
? ? ? ? ? }
? ? ? ? }, (item: Color) => item.toString())
? ? ? }
? ? ? .width('100%')
? ? ? .height(500)
? ? ? .backgroundColor('#f5f5f5')
? ? ? GridRow({ columns: 12 }) {
? ? ? ? ForEach(this.colors, (item: Color, index: number) => {
? ? ? ? ? GridCol({
? ? ? ? ? ? span: 2,
? ? ? ? ? ? order: 12 - index // 與文案相反排列
????????????// order: { xs: 1, sm: 2, md: 3, lg: 4 } //與span屬性類似,也支持分?jǐn)帱c(diǎn)傳值
? ? ? ? ? }) {
? ? ? ? ? ? Row() {
? ? ? ? ? ? ? Text(index.toString())
? ? ? ? ? ? ? ? .fontSize(20)
? ? ? ? ? ? ? ? .fontWeight(FontWeight.Bold)
? ? ? ? ? ? ? ? .width('100%')
? ? ? ? ? ? ? ? .textAlign(TextAlign.Center)
? ? ? ? ? ? }
? ? ? ? ? ? .backgroundColor(item)
? ? ? ? ? ? .width('100%')
? ? ? ? ? ? .height(50)
? ? ? ? ? }
? ? ? ? }, (item: Color) => item.toString())
? ? ? }
}
? ? .width('100%')
? }
}
