HarmonyOS鸿蒙Next中请教一下List使用为什么我无法成功拖动到底部完整显示
HarmonyOS鸿蒙Next中请教一下List使用为什么我无法成功拖动到底部完整显示
interface TitleItem {
name: string
}
const TitleList: TitleItem[] = [
{
name: '参会人'
},
{
name: '状态'
},
{
name: '类型'
},
{
name: '设备ID'
},
{
name: '界面'
},
{
name: '外部打开'
}
]
interface TerminalData {
devName: string
memberName: string
devId: number
type: string
status: number
face: number
flag: number
}
const TerminalList: TerminalData[] = [
{
devName: '设备',
memberName: '张三',
devId: 1,
type: '终端设备',
status: 0,
face: 1,
flag: 1
},
{
devName: '设备',
memberName: '李四',
devId: 2,
type: '终端设备',
status: 1,
face: 1,
flag: 1
},
{
devName: '设备',
memberName: '王五',
devId: 3,
type: '终端设备',
status: 1,
face: 1,
flag: 1
},
{
devName: '设备',
memberName: '赵六',
devId: 4,
type: '终端设备',
status: 1,
face: 1,
flag: 1
},
{
devName: '设备',
memberName: '牛七',
devId: 5,
type: '终端设备',
status: 0,
face: 1,
flag: 1
},
{
devName: '设备',
memberName: '参参会人参会人参会人参会人参会人参会人参会人参会人参会人参会人参会人参会人参会人参会人参会人参会人会人',
devId: 6,
type: '终端设备',
status: 1,
face: 1,
flag: 1
},
{
devName: '设备',
memberName: '参会参会人参会人参会人参会人参会人参会人人',
devId: 7,
type: '终端设备',
status: 1,
face: 1,
flag: 1
},
{
devName: '设备',
memberName: '参参会人参会人参会人参会人参会人参会人参会人参会人参会人参会人参会人会人',
devId: 8,
type: '终端设备',
status: 1,
face: 1,
flag: 1
},
{
devName: '设备',
memberName: '参参会人参会人参会人会人',
devId: 9,
type: '话筒设备',
status: 0,
face: 1,
flag: 1
},
{
devName: '设备',
memberName: '参会人',
devId: 10,
type: '投票设备',
status: 1,
face: 1,
flag: 1
},
{
devName: '设备',
memberName: '参会人',
devId: 11,
type: '投影设备',
status: 1,
face: 1,
flag: 1
}
]
@Builder
export function TerminalBuilder() {
TerminalLayout()
}
@ComponentV2
export struct TerminalLayout {
contacts: Array<TerminalData> = TerminalList
goodsNameData: Array<string> = [
'设备01', '设备02', '设备03', '设备04', '设备05', '设备06', '设备07', '设备08', '设备09', '设备10', '设备11'
]
titles: Array<TitleItem> = TitleList
titlesScroller = new Scroller();
verticalScroller = new Scroller();
@Local checkALl: boolean = false
@Builder
messageBuilder(index: number, content: string) {
Column() {
Text(content)
.fontSize('14vp')
.width('100%')
.height('100%')
.textAlign(TextAlign.Center)
}
.height('60vp')
.width('100vp')
.backgroundColor(index % 2 === 0 ? '#F0F3F5' : '#FFFFFF')
}
@Builder
titleBuilder() {
Row() {
ForEach(this.titles, (item: TitleItem, index: number) => {
Text(item.name)
.fontSize('16fp')
.fontColor('#FF7F8388')
// .width(this.fetchWeight(index))//所有标题分配100%
.layoutWeight(this.fetchWeight(index))
.textAlign(TextAlign.Center)
}, (item: TitleItem) => JSON.stringify(item))
}
.width('100%')
.height('34vp')
.backgroundColor('#FFFFFF')
}
fetchWeight(index: number) {
if (index == 0) {
return 3 //'30%'
} else if (index == 1) {
return 1 //"10%"
} else {
return 1.5 //"15%"
}
}
@Builder
listItemBuilder(item: TerminalData, index: number) {
Row() {
Row() { //分配100%
Text(item.memberName)
.buildText()
.layoutWeight(3)
Text(item.status == 1 ? '在线' : '离线')
.fontColor(item.status == 1 ? '#ff2cfc1a' : '#ffff5454')
.buildText()
.layoutWeight(1)
Text(item.type.toString())
.buildText()
.layoutWeight(1.5)
Text(item.devId.toString())
.buildText()
.layoutWeight(1.5)
Text(item.face.toString())
.buildText()
.layoutWeight(1.5)
Text(item.flag.toString())
.buildText()
.layoutWeight(1.5)
}.width('100%')
}
.width('100%')
.height('60vp')
.backgroundColor(index % 2 === 0 ? '#F0F3F5' : '#FFFFFF')
}
@Builder
listBuilder() {
List({ scroller: this.verticalScroller }) {
ListItemGroup({ header: this.titleBuilder() }) {
ForEach(this.contacts, (item: TerminalData, index: number) => {
ListItem() {
this.listItemBuilder(item, index)
}
})
}
}.sticky(StickyStyle.Header)
.edgeEffect(EdgeEffect.None)
.onScrollFrameBegin((offset: number) => {
this.titlesScroller.scrollBy(0, offset);
return { offsetRemain: 0 };
})
}
build() {
NavDestination() {
Column() {
Row() {
//左侧设备名称列表
Column() {
Text('设备名称')
.fontSize('16fp')
.fontColor('#FF7F8388')
.height('34vp')
.width('100vp')
.textAlign(TextAlign.Center)
Scroll(this.titlesScroller) {
List() {
ForEach(this.goodsNameData, (item: string, index: number) => {
ListItem() {
this.messageBuilder(index, item)
}
})
}
}
.scrollBar(BarState.Off)
.scrollable(ScrollDirection.Vertical)
.onDidScroll(() => {
this.verticalScroller.scrollTo({ xOffset: 0, yOffset: this.titlesScroller.currentOffset().yOffset });
})
}.width('100vp')
//右侧内容列表
Column() {
Scroll() {
this.listBuilder()
}
.width('120%') //这里关键配置
.scrollBar(BarState.Off)
.scrollable(ScrollDirection.Horizontal)
}
.layoutWeight(1)
}
.width('100%')
.layoutWeight(1)
// 底部其它功能按钮
Column({ space: 10 }) {
Row({ space: 10 }) {
Blank()
Button('上升').borderRadius(8)
Button('停止').borderRadius(8)
Button('下降').borderRadius(8)
Button('辅助签到').borderRadius(8)
Button('终端关机').borderRadius(8)
Button('终端重启').borderRadius(8)
Button('软件重启').borderRadius(8)
}.width('100%')
Row({ space: 10 }) {
Row() {
Checkbox({ name: 'cb1' })
.selectedColor(0xed6f21)
.shape(CheckBoxShape.ROUNDED_SQUARE)
.onChange((value: boolean) => {
console.info('全选:' + value)
})
Text('全选')
}
Row() {
Checkbox({ name: 'cb2' })
.selectedColor(0x39a2db)
.shape(CheckBoxShape.ROUNDED_SQUARE)
.onChange((value: boolean) => {
console.info('升降机:' + value)
})
Text('升降机')
}
Row() {
Checkbox({ name: 'cb3' })
.selectedColor(0x39a2db)
.shape(CheckBoxShape.ROUNDED_SQUARE)
.onChange((value: boolean) => {
console.info('话筒:' + value)
})
Text('话筒')
}
Blank()
Button('外部打开文档').borderRadius(8)
Button('网络唤醒').borderRadius(8)
Button('角色设定').borderRadius(8)
Button('发布机模式切换').borderRadius(8)
}.width('100%')
}
.width('100%')
.padding(10)
.background('#ffc4e6ff')
}
}
.title("终端控制")
.mode(NavDestinationMode.STANDARD)
.hideTitleBar(false)
.hideToolBar(true)
.onReady((context: NavDestinationContext) => {
//context.pathStack;
})
}
}
@Extend(Text)
function buildText() {
.fontSize('14fp')
.textAlign(TextAlign.Center)
}

效果就是像截图一样,往下拖就到底了,设备11 只显示一半
更多关于HarmonyOS鸿蒙Next中请教一下List使用为什么我无法成功拖动到底部完整显示的实战教程也可以访问 https://www.itying.com/category-93-b0.html
确实,添加了layoutWeight(1)就好了,感谢
Scroll(this.titlesScroller) {
List() {
ForEach(this.goodsNameData, (item: string, index: number) => {
ListItem() {
this.messageBuilder(index, item)
}
})
}
}
.layoutWeight(1)
.scrollBar(BarState.Off)
.scrollable(ScrollDirection.Vertical)
.onDidScroll(() => {
this.verticalScroller.scrollTo({ xOffset: 0, yOffset: this.titlesScroller.currentOffset().yOffset });
})
帮忙看下我底下新发现的情况,非常奇怪,
之前的布局使用了固定高度设置,导致在不同屏幕尺寸下,顶部内容区域无法自适应调整,设备11被底部按钮栏遮挡。

解决方案 :
采用了更灵活的空间分配方式,使用 layoutWeight 属性来自动分配屏幕空间:
interface TitleItem {
name: string
}
const TitleList: TitleItem[] = [
{
name: '参会人'
},
{
name: '状态'
},
{
name: '类型'
},
{
name: '设备ID'
},
{
name: '界面'
},
{
name: '外部打开'
}
]
interface TerminalData {
devName: string
memberName: string
devId: number
type: string
status: number
face: number
flag: number
}
const TerminalList: TerminalData[] = [
{
devName: '设备',
memberName: '张三',
devId: 1,
type: '终端设备',
status: 0,
face: 1,
flag: 1
},
{
devName: '设备',
memberName: '李四',
devId: 2,
type: '终端设备',
status: 1,
face: 1,
flag: 1
},
{
devName: '设备',
memberName: '王五',
devId: 3,
type: '终端设备',
status: 1,
face: 1,
flag: 1
},
{
devName: '设备',
memberName: '赵六',
devId: 4,
type: '终端设备',
status: 1,
face: 1,
flag: 1
},
{
devName: '设备',
memberName: '牛七',
devId: 5,
type: '终端设备',
status: 0,
face: 1,
flag: 1
},
{
devName: '设备',
memberName: '参参会人参会人参会人参会人参会人参会人参会人参会人参会人参会人参会人参会人参会人参会人参会人参会人会人',
devId: 6,
type: '终端设备',
status: 1,
face: 1,
flag: 1
},
{
devName: '设备',
memberName: '参会参会人参会人参会人参会人参会人参会人人',
devId: 7,
type: '终端设备',
status: 1,
face: 1,
flag: 1
},
{
devName: '设备',
memberName: '参参会人参会人参会人参会人参会人参会人参会人参会人参会人参会人参会人会人',
devId: 8,
type: '终端设备',
status: 1,
face: 1,
flag: 1
},
{
devName: '设备',
memberName: '参参会人参会人参会人会人',
devId: 9,
type: '话筒设备',
status: 0,
face: 1,
flag: 1
},
{
devName: '设备',
memberName: '参会人',
devId: 10,
type: '投票设备',
status: 1,
face: 1,
flag: 1
},
{
devName: '设备',
memberName: '参会人',
devId: 11,
type: '投影设备',
status: 1,
face: 1,
flag: 1
}
]
@Builder
export function TerminalBuilder() {
TerminalLayout()
}
@Entry
@ComponentV2
export struct TerminalLayout {
contacts: Array<TerminalData> = TerminalList
goodsNameData: Array<string> = [
'设备01', '设备02', '设备03', '设备04', '设备05', '设备06', '设备07', '设备08', '设备09', '设备10', '设备11'
]
titles: Array<TitleItem> = TitleList
titlesScroller = new Scroller();
verticalScroller = new Scroller();
@Local checkALl: boolean = false
@Builder
messageBuilder(index: number, content: string) {
Column() {
Text(content)
.fontSize('14vp')
.width('100%')
.height('100%')
.textAlign(TextAlign.Center)
}
.height('60vp')
.width('100vp')
.backgroundColor(index % 2 === 0 ? '#F0F3F5' : '#FFFFFF')
}
@Builder
titleBuilder() {
Row() {
ForEach(this.titles, (item: TitleItem, index: number) => {
Text(item.name)
.fontSize('16fp')
.fontColor('#FF7F8388')
// .width(this.fetchWeight(index))//所有标题分配100%
.layoutWeight(this.fetchWeight(index))
.textAlign(TextAlign.Center)
}, (item: TitleItem) => JSON.stringify(item))
}
.width('100%')
.height('34vp')
.backgroundColor('#FFFFFF')
}
fetchWeight(index: number) {
if (index == 0) {
return 3 //'30%'
} else if (index == 1) {
return 1 //"10%"
} else {
return 1.5 //"15%"
}
}
@Builder
listItemBuilder(item: TerminalData, index: number) {
Row() {
Row() { //分配100%
Text(item.memberName)
.buildText()
.layoutWeight(3)
Text(item.status == 1 ? '在线' : '离线')
.fontColor(item.status == 1 ? '#ff2cfc1a' : '#ffff5454')
.buildText()
.layoutWeight(1)
Text(item.type.toString())
.buildText()
.layoutWeight(1.5)
Text(item.devId.toString())
.buildText()
.layoutWeight(1.5)
Text(item.face.toString())
.buildText()
.layoutWeight(1.5)
Text(item.flag.toString())
.buildText()
.layoutWeight(1.5)
}.width('100%')
}
.width('100%')
.height('60vp')
.backgroundColor(index % 2 === 0 ? '#F0F3F5' : '#FFFFFF')
}
@Builder
listBuilder() {
List({ scroller: this.verticalScroller }) {
ListItemGroup({ header: this.titleBuilder() }) {
ForEach(this.contacts, (item: TerminalData, index: number) => {
ListItem() {
this.listItemBuilder(item, index)
}
})
}
}.sticky(StickyStyle.Header)
.edgeEffect(EdgeEffect.None)
.onScrollFrameBegin((offset: number) => {
this.titlesScroller.scrollBy(0, offset);
return { offsetRemain: 0 };
})
}
build() {
NavDestination() {
Column() {
Row() {
//左侧设备名称列表
Column() {
Text('设备名称')
.fontSize('16fp')
.fontColor('#FF7F8388')
.height('34vp')
.width('100vp')
.textAlign(TextAlign.Center)
Scroll(this.titlesScroller) {
List() {
ForEach(this.goodsNameData, (item: string, index: number) => {
ListItem() {
this.messageBuilder(index, item)
}
})
}
}
.scrollBar(BarState.Off)
.layoutWeight(1)
.onDidScroll(() => {
this.verticalScroller.scrollTo({ xOffset: 0, yOffset: this.titlesScroller.currentOffset().yOffset });
})
}
.width('100vp')
//右侧内容列表
Column() {
Scroll() {
this.listBuilder()
}
.width('120%') //这里关键配置
.scrollBar(BarState.Off)
}
.layoutWeight(1)
}
.width('100%')
.layoutWeight(1)
// 底部其它功能按钮
Column({ space: 10 }) {
Row({ space: 10 }) {
Blank()
Button('上升').borderRadius(8)
Button('停止').borderRadius(8)
Button('下降').borderRadius(8)
Button('辅助签到').borderRadius(8)
Button('终端关机').borderRadius(8)
Button('终端重启').borderRadius(8)
Button('软件重启').borderRadius(8)
}.width('100%')
Row({ space: 10 }) {
Row() {
Checkbox({ name: 'cb1' })
.selectedColor(0xed6f21)
.shape(CheckBoxShape.ROUNDED_SQUARE)
.onChange((value: boolean) => {
console.info('全选:' + value)
})
Text('全选')
}
Row() {
Checkbox({ name: 'cb2' })
.selectedColor(0x39a2db)
.shape(CheckBoxShape.ROUNDED_SQUARE)
.onChange((value: boolean) => {
console.info('升降机:' + value)
})
Text('升降机')
}
Row() {
Checkbox({ name: 'cb3' })
.selectedColor(0x39a2db)
.shape(CheckBoxShape.ROUNDED_SQUARE)
.onChange((value: boolean) => {
console.info('话筒:' + value)
})
Text('话筒')
}
Blank()
Button('外部打开文档').borderRadius(8)
Button('网络唤醒').borderRadius(8)
Button('角色设定').borderRadius(8)
Button('发布机模式切换').borderRadius(8)
}.width('100%')
}
.width('100%')
.padding(10)
.background('#ffc4e6ff')
}
}
.title("终端控制")
.mode(NavDestinationMode.STANDARD)
.hideTitleBar(false)
.hideToolBar(true)
.onReady((context: NavDestinationContext) => {
//context.pathStack;
})
}
}
@Extend(Text)
function buildText() {
.fontSize('14fp')
.textAlign(TextAlign.Center)
}
帮忙看下我底下新发现的情况,非常奇怪,
在HarmonyOS Next中,List组件默认使用弹性布局,可能导致内容未完全展开。检查是否设置了正确的布局参数,如listDirection为Vertical且未设置固定高度。确保List的父容器高度足够,或使用Scroll组件包裹。若使用ForEach渲染,确认数据源更新后触发了UI刷新。
从你的代码和截图来看,List无法拖动到底部完整显示的问题,主要是由于布局计算和滚动区域高度设置导致的。
核心问题在于:包裹右侧主列表的Scroll组件设置了.width('120%'),这会导致其宽度超出父容器,但更重要的是,它没有明确设置高度,或者其高度受到了父容器约束的影响,使得内部List的可滚动区域计算不完整。
解决方案:
-
为右侧的
Scroll组件明确设置高度,或者确保其父容器能提供正确的高度约束。最直接的方法是在listBuilder返回的List组件上设置高度,或者为包裹它的Scroll设置layoutWeight(1)来占满剩余空间。 -
调整你的
listBuilder函数,确保List能获得正确的高度。修改listBuilder中List的样式,为其设置一个明确的高度或使用layoutWeight。由于你的List是放在一个水平滚动的Scroll中,需要确保Scroll在垂直方向有确定的高度。
修改建议:
在你的build函数中,找到右侧内容列表部分,修改Scroll的样式:
//右侧内容列表
Column() {
Scroll() {
this.listBuilder()
}
.width('120%')
.height('100%') // 添加这行,确保Scroll有明确的高度
.scrollBar(BarState.Off)
.scrollable(ScrollDirection.Horizontal)
}
.layoutWeight(1)
或者,更推荐的方式是让listBuilder中的List自己决定高度,但需要确保其父容器(即这个Scroll)在垂直方向是撑满的。添加.height('100%')是最快的方法。
- 检查
ListItem的高度:你的listItemBuilder中每个ListItem高度固定为'60vp',11个数据项总高度应为660vp。确保外部容器高度足以容纳这个总高度,且没有其他元素(如底部按钮区域)遮挡或压缩了列表的滚动空间。
总结:问题根源是右侧可水平滚动的Scroll容器在垂直方向上高度未明确定义,导致其内部的List组件无法正确计算可滚动区域。通过为Scroll设置.height('100%')或类似明确的高度值,即可解决此问题。




