如何为Entry占位符添加自动滚动效果?
为CustomEntry的长占位符添加自动滚动效果
我正在使用一个无下划线的CustomEntry(Entry自定义控件),代码如下:
<renderer:CustomEntry x:Name="search_entry" Placeholder="Search by request id, requester's name, title, or description" Style="{StaticResource SearchEntryStyle}"/>
当前占位符文本过长,无法完整显示:

以下是两种实现占位符自动滚动的方案:
方案一:使用自定义渲染器(针对Xamarin.Forms)
通过原生平台渲染器实现原生级跑马灯效果,兼容性更强。
Android端实现
在Android项目中创建自定义渲染器:
[assembly: ExportRenderer(typeof(CustomEntry), typeof(CustomEntryMarqueeRenderer))] namespace YourAppNamespace.Droid.Renderers { public class CustomEntryMarqueeRenderer : EntryRenderer { protected override void OnElementChanged(ElementChangedEventArgs<Entry> e) { base.OnElementChanged(e); if (Control != null && !string.IsNullOrEmpty(Control.Hint)) { // 设置跑马灯截断方式 Control.Ellipsize = Android.Text.TextUtils.TruncateAt.Marquee; // 设置无限循环 Control.SetMarqueeRepeatLimit(-1); // 触发跑马灯需要控件处于选中状态 Control.Selected = true; Control.Focusable = true; Control.FocusableInTouchMode = true; } } } }
iOS端实现
在iOS项目中创建自定义渲染器:
[assembly: ExportRenderer(typeof(CustomEntry), typeof(CustomEntryMarqueeRenderer))] namespace YourAppNamespace.iOS.Renderers { public class CustomEntryMarqueeRenderer : EntryRenderer { private UILabel _placeholderLabel; private nfloat _originalX; protected override void OnElementChanged(ElementChangedEventArgs<Entry> e) { base.OnElementChanged(e); if (Control != null && !string.IsNullOrEmpty(Element.Placeholder)) { // 隐藏默认占位符 Control.Placeholder = string.Empty; // 创建自定义占位符Label _placeholderLabel = new UILabel { Text = Element.Placeholder, TextColor = UIColor.LightGray, Lines = 1, LineBreakMode = UILineBreakMode.Clip }; Control.AddSubview(_placeholderLabel); // 布局完成后记录初始位置并启动动画 Control.LayoutSubviews(); _originalX = _placeholderLabel.Frame.X; StartMarqueeAnimation(); } } private void StartMarqueeAnimation() { var maxOffset = _placeholderLabel.Frame.Width - Control.Frame.Width; if (maxOffset <= 0) return; UIView.Animate( duration: 5, // 滚动一次时长(秒) delay: 1, // 延迟1秒启动 options: UIViewAnimationOptions.Repeat | UIViewAnimationOptions.Autoreverse, animation: () => { _placeholderLabel.Frame = new CGRect(_originalX - maxOffset, _placeholderLabel.Frame.Y, _placeholderLabel.Frame.Width, _placeholderLabel.Frame.Height); }, completion: null); } } }
方案二:使用Xamarin.Forms行为(跨平台)
通过自定义ControlTemplate和Behavior实现跨平台滚动效果,无需修改原生代码。
1. 定义ControlTemplate
在资源字典中添加自定义Entry模板,将占位符替换为可动画的Label:
<ControlTemplate x:Key="AnimatedPlaceholderEntryTemplate"> <Grid> <Entry x:Name="EntryControl" Style="{TemplateBinding Style}" Text="{TemplateBinding Text}"/> <Label x:Name="PlaceholderLabel" Text="{TemplateBinding Placeholder}" TextColor="{TemplateBinding PlaceholderColor}" IsVisible="{TemplateBinding IsPlaceholderVisible}" HorizontalOptions="Start" VerticalOptions="Center"/> </Grid> </ControlTemplate>
2. 创建Marquee行为
public class MarqueePlaceholderBehavior : Behavior<CustomEntry> { private Label _placeholderLabel; private double _originalX; protected override void OnAttachedTo(CustomEntry entry) { base.OnAttachedTo(entry); entry.Appearing += OnEntryAppearing; } protected override void OnDetachingFrom(CustomEntry entry) { base.OnDetachingFrom(entry); entry.Appearing -= OnEntryAppearing; _placeholderLabel?.AbortAnimation("MarqueeAnimation"); } private void OnEntryAppearing(object sender, EventArgs e) { var entry = sender as CustomEntry; _placeholderLabel = entry?.FindByName<Label>("PlaceholderLabel"); if (_placeholderLabel == null || _placeholderLabel.Width <= entry.Width) return; _originalX = _placeholderLabel.TranslationX; StartMarqueeAnimation(); } private void StartMarqueeAnimation() { var maxOffset = _placeholderLabel.Width - _placeholderLabel.Parent.Width; _placeholderLabel.TranslateTo(_originalX - maxOffset, 0, 5000, Easing.Linear); _placeholderLabel.AnimationCompleted += (s, args) => { _placeholderLabel.TranslateTo(_originalX, 0, 0); StartMarqueeAnimation(); }; } }
3. 在XAML中使用
<renderer:CustomEntry x:Name="search_entry" Placeholder="Search by request id, requester's name, title, or description" Style="{StaticResource SearchEntryStyle}" ControlTemplate="{StaticResource AnimatedPlaceholderEntryTemplate}"> <renderer:CustomEntry.Behaviors> <local:MarqueePlaceholderBehavior/> </renderer:CustomEntry.Behaviors> </renderer:CustomEntry>
内容的提问来源于stack exchange,提问作者Sreejith Sree
相关产品推荐
相关产品推荐

