效果图
设计图如上。
代码如下Monitor.etf:
关键代码:在左侧list上下滑动的时候,调用:if (this.isLeftScroll) { this.rightYScroller.scrollTo({ xOffset: 0,yOffset: this.verticalOffset}) }
右侧List上下滑动的时候,调用:if (!this.isLeftScroll) { this.leftYScroller.scrollTo({ xOffset: 0,yOffset: this.verticalOffset}) }
已知问题:1,右侧滑动带动左侧上下滑动的时候流畅,但是左侧带动右侧滑动的时候,右侧数据栏List出现卡顿和闪烁,希望能看出问题的不吝指教。
2,横屏适配没处理。
import util from '@ohos.util';
import CommonConstants from '../../common/constants/CommonConstants';
import Logger from '../../common/utils/Logger';
import { MonitorNameCodeData } from '../../model/MonitorNameCodeData';
import { MonitorRightData } from '../../model/MonitorRightData';
import {MonitorNameCodeDataSource, MonitorRightListDataSource} from '../../model/MonitorModel'
import { NameCodeItem } from './MonitorNameCodeItem';
import display from '@ohos.display';
import { MonitorListItem } from './MonitorListItem';
import WindowModel from '../../model/WindowModel';
import { getMonitorPageHeight } from './MonitorPage';
/*
* 高度是全屏除去状态栏,底部导航栏,自选页Header(按钮区)
* */
export function getScreenWidthVp():number{
let disp=display.getDefaultDisplaySync();
let vpW:number=px2vp(disp.width);
return vpW;
}
export function getScreenHeightVp():number{
let disp=display.getDefaultDisplaySync();
let vpH:number=px2vp(disp.height);
return vpH;
}
getStatusBarHeight():number{
return 40;//此处省略从系统获取状态栏高度方法
}
export function getMonitorPageHeight():number{
return getScreenHeightVp()-getStatusBarHeight()-CommonConstants.TAB_BAR_HEIGHT_PORT;
}
export function getMonitorListHeight():number{
let listH:number=getMonitorPageHeight()-CommonConstants.MONITOR_HEADER_HEIGHT-CommonConstants.MONITOR_TITLE_HEIGHT;
Logger.info("compute monitor right list height:"+listH);
return listH;
}
@Component
export struct Monitor {
@State colWidth:number=0;
@State monitorTits:Resource[]=[$r('app.string.DN_LTRADE'),$r('app.string.DN_CHP_S'),$r('app.string.DN_CH_S'),
$r('app.string.DN_BID'),$r('app.string.DN_ASK'),$r('app.string.DN_HIGH'),$r('app.string.DN_LOW'),
$r('app.string.DN_OPRICE'),$r('app.string.DN_PCLOSE'), $r('app.string.DN_VOL'),$r('app.string.DN_TOVER')
];//total 24 lines
@Provide monitorNameCodeListener: MonitorNameCodeDataSource = new MonitorNameCodeDataSource();
@Provide monitorRightDataList: MonitorRightListDataSource = new MonitorRightListDataSource();
private leftYScroller: Scroller = new Scroller();
private rightYScroller: Scroller = new Scroller();
private verticalOffset:number=0;
private horizonOffset:number=0;
private isLeftScroll=false;
build() {
Row() {
Column(){//top left corner and name code column
Text("TopLeft")
.width(100))
.height(CommonConstants.MONITOR_TITLE_HEIGHT)
.backgroundColor(Color.Gray)
List({scroller: this.leftYScroller}){
LazyForEach(this.monitorNameCodeListener, (item: MonitorNameCodeData) => {
ListItem() {
NameCodeItem({ name: item.name, code: item.code })
.width(100))
.height(50)
.backgroundColor(Color.Yellow)
.borderWidth({ right: 0.5 })
} //ListItem
})//LazyForEach
}//List,如果子组件主轴方向总尺寸超过List父组件尺寸时,List主轴方向尺寸适应List的父组件尺寸。
.height(getMonitorListHeight())
.divider({ strokeWidth: 0.5, color: Color.Gray, startMargin: 5, endMargin: 5 })
.onTouch((event?: TouchEvent) => {
if (event === undefined) {
return;
}
switch (event.type) {
case TouchType.Down:
this.isLeftScroll=true;
break;
case TouchType.Up:
break;
case TouchType.Move:
break;
}
})
.onScroll((scrollOffset: number, scrollState: ScrollState) => {
this.verticalOffset = this.leftYScroller.currentOffset().yOffset;
this.horizonOffset=this.leftYScroller.currentOffset().xOffset;
if (this.isLeftScroll) {
this.rightYScroller.scrollTo({ xOffset: 0,yOffset: this.verticalOffset})
}
})
}//左侧名字代码列
.width(100)
.height('100%')
.justifyContent(FlexAlign.Start)
.backgroundColor(Color.Brown)
Scroll() {//right title and right data area
Column() {
List(){//title
ForEach(this.monitorTits,(item:string) => {
ListItem(){
Text(item)
.fontSize(18)
.width(70)
.height(CommonConstants.FULL_PARENT)
.backgroundColor(Color.Gray)
.textAlign(TextAlign.Center)
}
})
}//list title
.listDirection(Axis.Horizontal)
.height(CommonConstants.MONITOR_TITLE_HEIGHT)
List({scroller: this.rightYScroller}) {
LazyForEach(this.monitorRightDataList, (item: MonitorRightData) => {
ListItem() {
MonitorListItem({rightItem:item})
} //ListItem
})
}
.width(this.monitorTits.length * 70)
.height(getMonitorListHeight())
.divider({ strokeWidth: 0.5, color: Color.Gray, startMargin: 5, endMargin: 5 })
.onTouch((event?: TouchEvent) => {
if (event === undefined) {
return;
}
switch (event.type) {
case TouchType.Down:
this.isLeftScroll=false;
break;
case TouchType.Up:
break;
case TouchType.Move:
break;
}
})
.onScroll((scrollOffset: number, scrollState: ScrollState) => {
this.verticalOffset = this.rightYScroller.currentOffset().yOffset;
if (!this.isLeftScroll) {
this.leftYScroller.scrollTo({ xOffset: 0,yOffset: this.verticalOffset})
}
})
}
.height('100%')
}//右侧,标题和数据列
.width(WindowModel.getInstance().getScreenWidthVp()-100)
.height('100%')
.scrollable(ScrollDirection.Horizontal)
}//row
.alignItems(VerticalAlign.Top)//子组件在Row内部的排列方式
.width('100%')
.height(getMonitorPageHeight()-CommonConstants.MONITOR_HEADER_HEIGHT)
.backgroundColor('#00ff00')
}
}
MonitorRightData.ts
import { MonitorData } from './MonitorData';
export class MonitorRightData extends MonitorData{
rightDatas:string[]=["29999.99","+199","0.67%","29999.00","30000","30100","29700.00","29699.59","29899.00","12345","123456789"];
constructor() {
super();
}
}
export const rightDatas: MonitorRightData[]=[
new MonitorRightData(),
new MonitorRightData(),
new MonitorRightData(),
new MonitorRightData(),
new MonitorRightData()
];
MonitorListItem.ets
import CommonConstants from '../../common/constants/CommonConstants'
import { MonitorRightData } from '../../model/MonitorRightData';
@Component
export struct MonitorListItem{
private rightItem:MonitorRightData=new MonitorRightData();
build(){
Row() {
ForEach(this.rightItem.rightDatas, (itemRight: string) => {
Text(itemRight)
.width(70)
.height(CommonConstants.FULL_PARENT)
.backgroundColor(Color.White)
.textAlign(TextAlign.End)
.maxLines(1)
.borderWidth({ right: 0.5 })
.borderColor(Color.Gray)
.textOverflow({ overflow: TextOverflow.Ellipsis })
})
} //Row
.width(CommonConstants.FULL_PARENT)
.height(50)
.backgroundColor(Color.Brown)
}
}
MonitorNameCodeItem.ets
import CommonConstants from '../../common/constants/CommonConstants';
@Component
export struct NameCodeItem{
@State name:string="";
@State code:string="";
build() {
Column() {
Text(this.name)
.width(CommonConstants.FULL_PARENT)
.layoutWeight(5)
.fontColor(Color.Brown)
.backgroundColor(Color.White)
.fontSize(20)
.fontWeight(FontWeight.Bold)
.maxLines(1)
Text(this.code).fontSize(14)
.width(CommonConstants.FULL_PARENT)
.layoutWeight(3)
.fontColor(Color.Black)
.backgroundColor(Color.White)
.maxLines(1)
} //name and code col fistcol
.alignItems(HorizontalAlign.Start)
.justifyContent(FlexAlign.Start)
}
}
MonitorModel.ts
// Basic implementation of IDataSource to handle data listener
import CommonConstants from '../common/constants/CommonConstants';
import { MonitorData } from './MonitorData';
import { nameCodeDatas,MonitorNameCodeData } from './MonitorNameCodeData';
import { rightDatas,MonitorRightData } from './MonitorRightData'
const createNameCodeRange = (): MonitorNameCodeData[] => {
let result = new Array<MonitorNameCodeData>();
for (let i = 0; i < 4; i++) {
result = result.concat(nameCodeDatas);
}
return result;
}
const createRightListRange = (): MonitorRightData[] => {
let result = new Array<MonitorRightData>();
for (let i = 0; i < 4; i++) {
result = result.concat(rightDatas);
}
return result;
}
// @ts-ignore
class BasicDataSource implements IDataSource {
// @ts-ignore
private listeners: DataChangeListener[] = [];
private originDataArray: MonitorData[] = [];
public totalCount(): number {
return 0;
}
public getData(index: number): MonitorData {
return this.originDataArray[index];
}
// 该方法为框架侧调用,为LazyForEach组件向其数据源处添加listener监听
// @ts-ignore
registerDataChangeListener(listener: DataChangeListener): void {
if (this.listeners.indexOf(listener) < 0) {
console.info('add listener');
this.listeners.push(listener);
}
}
// 该方法为框架侧调用,为对应的LazyForEach组件在数据源处去除listener监听
// @ts-ignore
unregisterDataChangeListener(listener: DataChangeListener): void {
const pos = this.listeners.indexOf(listener);
if (pos >= 0) {
console.info('remove listener');
this.listeners.splice(pos, 1);
}
}
// 通知LazyForEach组件需要重载所有子组件
notifyDataReload(): void {
this.listeners.forEach(listener => {
listener.onDataReloaded();
})
}
// 通知LazyForEach组件需要在index对应索引处添加子组件
notifyDataAdd(index: number): void {
this.listeners.forEach(listener => {
listener.onDataAdd(index);
})
}
// 通知LazyForEach组件在index对应索引处数据有变化,需要重建该子组件
notifyDataChange(index: number): void {
this.listeners.forEach(listener => {
listener.onDataChange(index);
})
}
// 通知LazyForEach组件需要在index对应索引处删除该子组件
notifyDataDelete(index: number): void {
this.listeners.forEach(listener => {
listener.onDataDelete(index);
})
}
}
export class MonitorNameCodeDataSource extends BasicDataSource {
private listData = createNameCodeRange();
public totalCount(): number {
return this.listData.length;
}
public getData(index: number): MonitorData {
return this.listData[index];
}
public pushData(): void {
if (this.listData.length < CommonConstants.MONITOR_MAX_LENGTH) {
// this.listData = [...this.listData, ...goodsInitialList];
this.listData.concat(nameCodeDatas);
this.notifyDataAdd(this.listData.length - 1);
}
}
}
export class MonitorRightListDataSource extends BasicDataSource {
private listData = createRightListRange();
public totalCount(): number {
return this.listData.length;
}
public getData(index: number): MonitorRightData {
return this.listData[index];
}
public pushData(): void {
if (this.listData.length < CommonConstants.MONITOR_MAX_LENGTH) {
// this.listData = [...this.listData, ...goodsInitialList];
this.listData.concat(rightDatas);
this.notifyDataAdd(this.listData.length - 1);
}
}
}
CommonConstants.ts
export default class CommonConstants {
static readonly FULL_PARENT = '100%';
static readonly MONITOR_MAX_LENGTH = 100;
static readonly TAB_BAR_HEIGHT_PORT=56;//系统默认值为56vp
static readonly MONITOR_HEADER_HEIGHT=50;
static readonly MONITOR_TITLE_HEIGHT=50;
}
参考
鸿蒙两个Scroll互相监听彼此的滑动-卡顿问题_坚果的博客的博客-CSDN博客