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

时间:2018-01-23 17:34:39

标签: c# xamarin mvvm xamarin.forms

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

这是我的方法:

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

这是我的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。我把整个View绑定到了我的ViewModel,是这个原因?如果你必须遵循MVVM模式,怎么会接近呢?

值得一提的是,我尝试了this方法。但是,它并没有按预期工作。只有当我点击编辑器然后取消选中它时,才会显示占位符。它应该像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>

2 个答案:

答案 0 :(得分:1)

您正在寻找的是自定义渲染器,您可以看到,因为Xamarin.Forms只是本机元素的另一个级别,您可以使用CustomRenderer“访问”本机元素:

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());
        }
    }
}

的iOS:

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/

答案 1 :(得分:1)

以下是您自己提到的方法:

<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>

这是Viewmodel部分:

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