如何在 Xamarin 窗体的编辑器中实现占位符?



我读到编辑器控件没有占位符,所以我一直在尝试做一个解决方法,但没有成功。我知道 Entry 控件有一个占位符,但我需要多行字段,因为我将把它用作用户可以编写注释的字段,而不仅仅是一行。

这是我的方法:

我尝试将编辑器和标签放入网格控件中,标签位于编辑器的顶部。编辑器的InputTransparent标志设置为true。然后,我只需根据Editor是否有文本来切换标签的IsVisible属性。但是,问题是我使用的是MVVM模式,因此我不知道如何控制ViewModel中的TextChanged事件。我也尝试在后面编码,但找不到标签的名称。

这是我的 XAML 代码 - 只发布了相关代码:

<Grid Grid.Row="1">
<Editor Text="{Binding UserComment, Mode=TwoWay}" TextChanged="EditorTextChanged"                                          HorizontalOptions="FillAndExpand"/>
<Label x:Name="PlaceholderLabel" Text="Write a comment" InputTransparent="True"                                             HorizontalOptions="StartAndExpand"/>
</Grid>

目前,在代码隐藏中,我只有EditorTextChanged事件,它工作正常,但它找不到PlaceholderLabel。我已经将整个视图绑定到我的视图模型,这是原因吗?如果您必须遵循 MVVM 模式,将如何处理它?

值得一提的是,我已经尝试过这种方法。但是,它没有按预期工作。占位符仅在我单击编辑器然后取消单击它时才会出现。它应该像在Facebook上一样出现在开头。

编辑

这是整个 XAML 代码:

<ContentPage.Resources>
<ResourceDictionary>
<local:TeamAlignmentConverter x:Key="teamConverter"/>
<local:ImageAlignmentConverter x:Key="imageConverter"/>
<local:BooleanReverser x:Key="booleanReverser"/>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout VerticalOptions="FillAndExpand" Spacing="5">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="180"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.BindingContext>
<viewModel:MatchPageVM/>
</Grid.BindingContext>
<Grid BackgroundColor="White" RowSpacing="0" Grid.Row="0">
<Grid.RowDefinitions>
<RowDefinition Height="0.5*" />
<RowDefinition Height="2*" />
<RowDefinition Height="0.8*" />
</Grid.RowDefinitions>
<Label Text="{Binding Teams}" FontSize="26" HorizontalOptions="CenterAndExpand" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" VerticalOptions="CenterAndExpand" Grid.Row="0"/>
<Image Source="notificationsbell.png" Margin="25,10,0,0" HorizontalOptions="StartAndExpand" VerticalOptions="CenterAndExpand" Grid.Row="1"/>
<Label Text="{Binding Score}" FontSize="80" HorizontalOptions="CenterAndExpand" HorizontalTextAlignment="Center" VerticalOptions="CenterAndExpand" VerticalTextAlignment="Center" Grid.Row="1"/>
<Label Text="Live" FontSize="24" HorizontalOptions="CenterAndExpand" HorizontalTextAlignment="Center" VerticalOptions="CenterAndExpand" VerticalTextAlignment="Center" Grid.Row="2"/>
</Grid>

</Grid>
<Grid RowSpacing="0" VerticalOptions="FillAndExpand">
<Grid.BindingContext>
<viewModel:MatchPageVM/>
</Grid.BindingContext>
<cv:CarouselView ItemsSource="{Binding CollectionList}">
<cv:CarouselView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<flv:FlowListView x:Name="flowListView" FlowColumnCount="1" Grid.Row="0"
SeparatorVisibility="None" HasUnevenRows="True"  IsVisible="{Binding ListSwitch}"
FlowItemsSource="{Binding CollectionList}" BackgroundColor="White" >
<flv:FlowListView.FlowColumnTemplate>
<DataTemplate>
<Grid ColumnSpacing="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="0.5*"/>
<ColumnDefinition Width="0.005*"/>
<ColumnDefinition Width="0.5*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Text="{Binding PlayerName}" Grid.Column="{Binding Team}" VerticalOptions="Center" 
HorizontalOptions="FillAndExpand" 
HorizontalTextAlignment="{Binding Team, Converter={StaticResource teamConverter}}"/>
<Image Source="{Binding ImageURL}" HorizontalOptions="Center" Grid.Column="{Binding Team, Converter={StaticResource imageConverter}}" Aspect="AspectFill" VerticalOptions="Center"/>
<BoxView BackgroundColor="Black" Grid.Column="2" HeightRequest="20" VerticalOptions="Center"/>
</Grid>
</DataTemplate>
</flv:FlowListView.FlowColumnTemplate>
</flv:FlowListView>
<Grid Grid.Row="0">
<Grid.RowDefinitions>
<RowDefinition Height="4*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<flv:FlowListView x:Name="flowListView2" FlowColumnCount="1" BackgroundColor="White"
HasUnevenRows="True" HeightRequest="180" IsVisible="{Binding ListSwitch, Converter={StaticResource booleanReverser}}" Grid.Row="0"
FlowItemsSource="{Binding CollectionList}" SeparatorVisibility="Default" SeparatorColor="Black">
<flv:FlowListView.FlowColumnTemplate>
<DataTemplate>
<Grid RowSpacing="5">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2.5*"/>
<ColumnDefinition Width="20*"/>
</Grid.ColumnDefinitions>
<Image Source="{Binding ImageURL}" HorizontalOptions="Start" 
Grid.Row="0" Grid.Column="0" Aspect="AspectFit" Margin="0,10,0,0" VerticalOptions="Start"/>
<Label Text="{Binding UserName}" Grid.Row="0" Grid.Column="1" VerticalOptions="Start" 
HorizontalOptions="Start" FontSize="Medium" FontAttributes="Bold" HorizontalTextAlignment="Start" Margin="0,10,0,5" />
<Label Text="{Binding UserComment}" Grid.Row="1" Grid.Column="0" VerticalOptions="Start" 
HorizontalOptions="StartAndExpand" FontSize="Medium" HorizontalTextAlignment="Start" Grid.ColumnSpan="2" Margin="0,0,0,10" />
</Grid>
</DataTemplate>
</flv:FlowListView.FlowColumnTemplate>
</flv:FlowListView>
<Grid Grid.Row="1" IsVisible="{Binding ListSwitch, Converter={StaticResource booleanReverser}}">
<Editor Text="{Binding UserComment, Mode=TwoWay}"
HorizontalOptions="FillAndExpand">
<Editor.BindingContext>
<viewModel:MatchPageVM/>
</Editor.BindingContext>
</Editor>
<Label Text="Skriv en kommentar" 
HorizontalOptions="StartAndExpand" IsVisible="{Binding LabelIsVisible}" InputTransparent="True">
<Label.BindingContext>
<viewModel:MatchPageVM/>
</Label.BindingContext>
</Label>
</Grid>
</Grid>
</Grid>
</DataTemplate>
</cv:CarouselView.ItemTemplate>
</cv:CarouselView>
</Grid>
</StackLayout>
</ContentPage.Content>

这是您自己提到的确实有效的方法:

<AbsoluteLayout
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
<Editor
Text="{Binding Address, Mode=TwoWay}"
HorizontalOptions="FillAndExpand"
AbsoluteLayout.LayoutFlags="PositionProportional, WidthProportional"
AbsoluteLayout.LayoutBounds="0,0,1.01,100">
</Editor>
<Label Text="MyPlaceHolder" IsVisible="{Binding IsAddrerssPlaceHolderVisible}" HorizontalTextAlignment="Center"
AbsoluteLayout.LayoutBounds="0.5,0.5, 1, 0.5" VerticalTextAlignment="Center"
AbsoluteLayout.LayoutFlags="All" InputTransparent="True"/>
</AbsoluteLayout>

这是视图模型部分:

public bool IsAddrerssPlaceHolderVisible
{
get => _isAddrerssPlaceHolderVisible;
set
{
_isAddrerssPlaceHolderVisible= value;
RaisePropertyChanged();
}
}
public string Address
{
get => _address;
set
{
_address = value;
if (value.Length > 0)
{
IsAddrerssPlaceHolderVisible= false;
}
else
{
IsAddrerssPlaceHolderVisible= true;
}
RaisePropertyChanged();
}
}

它甚至不需要我之前错误提到的任何其他东西!它的工作原理就这么简单:D

您正在寻找的是自定义呈现器,您会看到由于 Xamarin.Forms 只是本机元素的另一个级别,您可以使用自定义渲染器"访问"本机元素:

https://developer.xamarin.com/guides/xamarin-forms/application-fundamentals/custom-renderer/

您可以创建基本的自定义编辑器:

using Xamarin.Forms;
namespace EditorWithPlaceholder
{
public class PlaceholderEditor : Editor
{
public static BindableProperty PlaceholderProperty
= BindableProperty.Create(nameof(Placeholder), typeof(string), typeof(PlaceholderEditor));
public static BindableProperty PlaceholderColorProperty
= BindableProperty.Create(nameof(PlaceholderColor), typeof(Color), typeof(PlaceholderEditor), Color.Gray);
public string Placeholder
{
get { return (string) GetValue(PlaceholderProperty); }
set { SetValue(PlaceholderProperty, value); }
}
public Color PlaceholderColor
{
get { return (Color) GetValue(PlaceholderColorProperty); }
set { SetValue(PlaceholderColorProperty, value); }
}
}
}

以及每个平台上的渲染器:

人造人:

using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(PlaceholderEditor), typeof(PlaceholderEditorRenderer))]
namespace EditorWithPlaceholder.Droid.Renderers
{
public class PlacehoderEditorRenderer : EditorRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
{
base.OnElementChanged(e);
if (Element == null)
return;
var element = (PlaceholderEditor) Element;
Control.Hint = element.Placeholder;
Control.SetHintTextColor(element.PlaceholderColor.ToAndroid());
}
}
}

苹果:

using System;
using Cirrious.FluentLayouts.Touch;
using Foundation;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer(typeof(PlaceholderEditor), typeof(PlaceholderEditorRenderer))]
namespace EditorWithPlaceholder.iOS.Renderers
{
public class PlaceholderEditorRenderer : EditorRenderer
{
private UILabel _placeholderLabel;
protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
{
base.OnElementChanged(e);
if (Element == null)
return;
CreatePlaceholderLabel((PlaceholderEditor) Element, Control);
Control.Ended += OnEnded;
Control.TextChanged += OnChanged;
}
private void CreatePlaceholderLabel(PlaceholderEditor element, UITextView parent)
{
_placeholderLabel = new UILabel
{
Text = element.Placeholder,
TextColor = element.PlaceholderColor.ToUIColor(),
BackgroundColor = UIColor.Clear,
Font = UIFont.FromName(element.FontFamily, (nfloat)element.FontSize)
};
_placeholderLabel.SizeToFit();
parent.AddSubview(_placeholderLabel);
parent.SubviewsDoNotTranslateAutoresizingMaskIntoConstraints();
parent.AddConstraints(
_placeholderLabel.AtLeftOf(parent, 7),
_placeholderLabel.WithSameCenterY(parent)
);
parent.LayoutIfNeeded();
_placeholderLabel.Hidden = parent.HasText;
}
private void OnEnded(object sender, EventArgs args)
{
if (!((UITextView) sender).HasText && _placeholderLabel != null)
_placeholderLabel.Hidden = false;
}
private void OnChanged(object sender, EventArgs args)
{
if (_placeholderLabel != null)
_placeholderLabel.Hidden = ((UITextView) sender).HasText;
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
Control.Ended -= OnEnded;
Control.Changed -= OnChanged;
_placeholderLabel?.Dispose();
_placeholderLabel = null;
}
base.Dispose(disposing);
}
}
}

我希望这些信息有所帮助。

供参考: https://solidbrain.com/2017/07/10/placeholder-text-in-xamarin-forms-editor/

最新更新