FMX ListView动态外观模式下仅Text可改 宽度等属性设置不生效
FMX ListView动态外观模式下TListItemText宽度修改不生效问题
问题场景
在FMX框架下使用ListView控件,添加若干TListItemText元素并设置初始尺寸与位置,填充数据时发现部分文本项因宽度不足被截断。
最初尝试在OnUpdatingObjects事件中通过Canvas.TextWidth计算文本宽度后额外增加10像素调整所有文本项宽度,实现代码如下:
var Drawable : TListItemText; Text : String; i : integer; begin for i := 0 to AItem.Objects.Count-1 do begin if AItem.View.Drawables[i].ClassName = 'TListItemText' then begin Drawable := TlistItemText(AItem.Objects.Drawables[i]); Text := Drawable.Text; Drawable.Width := Round(Canvas.TextWidth(Text))+10; end; end; end;
运行后宽度设置未生效,即使手动硬编码指定名称为MyText的TListItemText宽度为200依然无效果:
TListItemText(Objects.FindDrawable('MyText')).Width := 200;
已知前提
- 当前ListView采用*DynamicAppearance(动态外观)*模式
- 调试时Drawable变量的Width属性确实显示为新设置值,但ListView界面无对应渲染变化,目前除Text属性外其余属性修改均无法生效
问题原因
核心原因是事件时机不对,被ListView内置布局逻辑覆盖了设置:
OnUpdatingObjects事件的设计用途是增删Item内的Drawable对象、更新绑定的文本/图片类数据,触发时机在ListView默认布局流程之前。你在事件里手动修改的Width、Position等布局属性,会在事件执行完成后,被ListView根据外观设计时存储的默认值重置覆盖,所以调试时能看到属性被修改,但最终渲染时会回到初始配置。- DynamicAppearance模式默认会对所有Drawable对象执行统一的固定布局计算,默认逻辑不会主动读取你运行时修改的布局属性值。
解决方案
方案1:换用正确的事件修改(轻量实现,适配绝大多数场景)
不要在OnUpdatingObjects里调整布局,改用OnItemCustomize事件,修改前先关闭控件的自动对齐约束,避免属性被覆盖:
procedure TForm1.ListView1ItemCustomize(const Sender: TObject; const AItem: TListViewItem); var Drawable : TListItemText; begin Drawable := TListItemText(AItem.Objects.FindDrawable('MyText')); if not Assigned(Drawable) then Exit; // 关闭自动对齐,阻止默认布局覆盖尺寸设置 Drawable.Align := TAlignLayout.None; // 计算宽度时必须传入文本自身的字体属性,避免计算偏差 Drawable.Width := Round(ListView1.Canvas.TextWidth(Drawable.Text, Drawable.Font)) + 10; // 触发重绘刷新 Drawable.ResetEffects; end;
如果只是需要避免文本被截断不需要固定行高,也可以直接把对应TListItemText的WordWrap属性设为True、Trimming属性设为TTextTrimming.None,控件会自动换行适配内容,不需要手动计算宽度。
方案2:自定义Drawable类(适配复杂动态布局场景)
如果每个Item的布局差异极大,需要频繁调整尺寸位置,最稳定的方式是继承TListItemText重写DoUpdate方法,在方法内部完成文本宽度计算和尺寸调整,直接接管该元素的布局逻辑,跳过默认布局流程的覆盖。
内容的提问来源于stack exchange,提问作者Geovanii Amaral
相关产品推荐
相关产品推荐

