如何让文本换行并在 Xamarin Forms iOS 自定义渲染器下方添加另一行?
How do I get text to wrap and add another line below in a Xamarin Forms iOS custom renderer?
我正在创建自定义渲染器以在图像上以半透明的白色 space 显示标题和说明。如果标题比图像宽,则标题应换行到第二行,如果有空间,下面可能会显示可选的描述。在 Android 中,我可以使用 StaticLayout 来做到这一点:
// Create text rectangle
var height = Height / 3;
canvas.Save();
canvas.ClipRect(0, Height - height, Width, Height);
canvas.DrawARGB(191, 255, 255, 255);
canvas.Restore();
var item = ((ImageTile) Element).Item;
var textSize = (height - 15) / 2;
var textPaint = new TextPaint
{
StrokeWidth = 5,
TextSize = textSize,
FakeBoldText = true,
};
if (Build.VERSION.SdkInt >= BuildVersionCodes.Honeycomb)
SetLayerType(LayerType.Software, textPaint);
textPaint.SetStyle(Paint.Style.Fill);
textPaint.Color = global::Android.Graphics.Color.Black;
// init StaticLayout for text
var titleLayout = new StaticLayout(
item.Title, textPaint, Width - 10, Android.Text.Layout.Alignment.AlignNormal, 1.0f, 0.0f, false);
canvas.Translate(5, Height - height + 5);
titleLayout.Draw(canvas);
canvas.Restore();
textPaint = new TextPaint
{
StrokeWidth = 4,
TextSize = textSize - 10,
};
if (Build.VERSION.SdkInt >= BuildVersionCodes.Honeycomb)
SetLayerType(LayerType.Software, textPaint);
var descLayout = new StaticLayout(
item.Description, textPaint, Width - 10, Android.Text.Layout.Alignment.AlignNormal, 1.0f, 0.0f, false);
canvas.Translate(5, Height - height + titleLayout.Height + 5);
descLayout.Draw(canvas);
canvas.Restore();
在 iOS 我正在使用 CATextLayers,但我无法让文本换行,即使我定义了框架并将 Wrapped 设置为 true 并将 TextTruncationMode 设置为 None。我也不知道如何获得 tilteLayer 的实际高度,所以我可以将 descLayer 放在它下面。这是我目前所拥有的,它在没有换行的情况下将标题和描述绘制在彼此之上。
var textLayer = new CALayer();
var textRec = new CGRect(0, element.HeightRequest - textheight, element.WidthRequest,
textheight);
textLayer.Frame = textRec;
var backgroundcolor = Color.FromRgba(255, 255, 255, .25).ToCGColor();
textLayer.BackgroundColor = backgroundcolor;
Control.Layer.AddSublayer(textLayer);
var titleLayer = new CATextLayer
{
String = element.Item.Title,
ForegroundColor = Color.Black.ToCGColor(),
FontSize = 14,
Wrapped = true,
TextTruncationMode = CATextLayerTruncationMode.None,
TextAlignmentMode = CATextLayerAlignmentMode.Left,
//Bounds = new CGRect(2, element.HeightRequest - textheight + 2, element.WidthRequest - 4,
// textheight - 4),
};
var titleRec = new CGRect(2, element.HeightRequest - textheight + 2, element.WidthRequest - 4,
textheight - 4);
titleLayer.Frame = titleRec;
Control.Layer.AddSublayer(titleLayer);
var descLayer = new CATextLayer
{
String = element.Item.Description,
ForegroundColor = Color.Black.ToCGColor(),
FontSize = 12,
Wrapped = true,
TextTruncationMode = CATextLayerTruncationMode.None,
};
var descRec = new CGRect(2, element.HeightRequest - textheight + 2, element.WidthRequest - 4,
textheight - 4);
descLayer.ContentsRect = descRec;
Control.Layer.AddSublayer(descLayer);
为什么不试试 autoLayout?您想要在原始图像上添加背景视图和两种类型的文本。 CALayer
可以达到你的效果,但它不能使用autoLayout,所以你需要使用硬代码(计算文本高度和图层位置)来构造它。你也说
I am unable to get the text to wrap. And I also don't know how to get
the actual height of the tilteLayer so I can position the descLayer
below it.
在图像的自定义渲染器中,由于此控件尚未渲染,因此其 Frame
和 HeightRequest
也是未知的。这样你就不会得到正确的框架,层也不会,所以文本不会显示。我认为最好的方法是使用 AutoLayout:
// Create a view to hold content just like your textLayer
UIView bgView = new UIView();
bgView.BackgroundColor = UIColor.FromRGBA(1, 1, 1, 0.25f);
bgView.TranslatesAutoresizingMaskIntoConstraints = false;
Control.AddSubview(bgView);
bgView.LeadingAnchor.ConstraintEqualTo(Control.LeadingAnchor).Active = true;
bgView.TopAnchor.ConstraintGreaterThanOrEqualTo(Control.TopAnchor).Active = true;
bgView.TrailingAnchor.ConstraintEqualTo(Control.TrailingAnchor).Active = true;
bgView.BottomAnchor.ConstraintEqualTo(Control.BottomAnchor).Active = true;
UILabel titleLabel = new UILabel();
bgView.AddSubview(titleLabel);
titleLabel.TranslatesAutoresizingMaskIntoConstraints = false;
// Set this property to 0, then your label will move to several lines if your text is too large.
titleLabel.Lines = 0;
titleLabel.Font = UIFont.SystemFontOfSize(14);
titleLabel.Text = Element.Item.Title;
titleLabel.LeadingAnchor.ConstraintEqualTo(bgView.LeadingAnchor).Active = true;
titleLabel.TopAnchor.ConstraintEqualTo(bgView.TopAnchor).Active = true;
titleLabel.TrailingAnchor.ConstraintEqualTo(bgView.TrailingAnchor).Active = true;
// This constraint will show the titleLabel's content at high priority. It means show the descLabel if the image has enough place.
titleLabel.SetContentHuggingPriority(249, UILayoutConstraintAxis.Vertical);
UILabel descLabel = new UILabel();
bgView.AddSubview(descLabel);
descLabel.TranslatesAutoresizingMaskIntoConstraints = false;
descLabel.Lines = 0;
descLabel.Text = Element.Item.Description;
descLabel.Font = UIFont.SystemFontOfSize(12);
descLabel.LeadingAnchor.ConstraintEqualTo(bgView.LeadingAnchor).Active = true;
descLabel.TopAnchor.ConstraintEqualTo(titleLabel.BottomAnchor).Active = true;
descLabel.TrailingAnchor.ConstraintEqualTo(bgView.TrailingAnchor).Active = true;
descLabel.BottomAnchor.ConstraintEqualTo(bgView.BottomAnchor).Active = true;
这样bgView会根据titleLabel和descLabel展开高度。最大高度将是原始图像的高度。此外,titleLabel 将根据其内容自动计算其大小。此外,如果房间允许,descLabel 将始终位于 titleLabel 下方。
您可以调整这些限制以满足您自己的要求。
我正在创建自定义渲染器以在图像上以半透明的白色 space 显示标题和说明。如果标题比图像宽,则标题应换行到第二行,如果有空间,下面可能会显示可选的描述。在 Android 中,我可以使用 StaticLayout 来做到这一点:
// Create text rectangle
var height = Height / 3;
canvas.Save();
canvas.ClipRect(0, Height - height, Width, Height);
canvas.DrawARGB(191, 255, 255, 255);
canvas.Restore();
var item = ((ImageTile) Element).Item;
var textSize = (height - 15) / 2;
var textPaint = new TextPaint
{
StrokeWidth = 5,
TextSize = textSize,
FakeBoldText = true,
};
if (Build.VERSION.SdkInt >= BuildVersionCodes.Honeycomb)
SetLayerType(LayerType.Software, textPaint);
textPaint.SetStyle(Paint.Style.Fill);
textPaint.Color = global::Android.Graphics.Color.Black;
// init StaticLayout for text
var titleLayout = new StaticLayout(
item.Title, textPaint, Width - 10, Android.Text.Layout.Alignment.AlignNormal, 1.0f, 0.0f, false);
canvas.Translate(5, Height - height + 5);
titleLayout.Draw(canvas);
canvas.Restore();
textPaint = new TextPaint
{
StrokeWidth = 4,
TextSize = textSize - 10,
};
if (Build.VERSION.SdkInt >= BuildVersionCodes.Honeycomb)
SetLayerType(LayerType.Software, textPaint);
var descLayout = new StaticLayout(
item.Description, textPaint, Width - 10, Android.Text.Layout.Alignment.AlignNormal, 1.0f, 0.0f, false);
canvas.Translate(5, Height - height + titleLayout.Height + 5);
descLayout.Draw(canvas);
canvas.Restore();
在 iOS 我正在使用 CATextLayers,但我无法让文本换行,即使我定义了框架并将 Wrapped 设置为 true 并将 TextTruncationMode 设置为 None。我也不知道如何获得 tilteLayer 的实际高度,所以我可以将 descLayer 放在它下面。这是我目前所拥有的,它在没有换行的情况下将标题和描述绘制在彼此之上。
var textLayer = new CALayer();
var textRec = new CGRect(0, element.HeightRequest - textheight, element.WidthRequest,
textheight);
textLayer.Frame = textRec;
var backgroundcolor = Color.FromRgba(255, 255, 255, .25).ToCGColor();
textLayer.BackgroundColor = backgroundcolor;
Control.Layer.AddSublayer(textLayer);
var titleLayer = new CATextLayer
{
String = element.Item.Title,
ForegroundColor = Color.Black.ToCGColor(),
FontSize = 14,
Wrapped = true,
TextTruncationMode = CATextLayerTruncationMode.None,
TextAlignmentMode = CATextLayerAlignmentMode.Left,
//Bounds = new CGRect(2, element.HeightRequest - textheight + 2, element.WidthRequest - 4,
// textheight - 4),
};
var titleRec = new CGRect(2, element.HeightRequest - textheight + 2, element.WidthRequest - 4,
textheight - 4);
titleLayer.Frame = titleRec;
Control.Layer.AddSublayer(titleLayer);
var descLayer = new CATextLayer
{
String = element.Item.Description,
ForegroundColor = Color.Black.ToCGColor(),
FontSize = 12,
Wrapped = true,
TextTruncationMode = CATextLayerTruncationMode.None,
};
var descRec = new CGRect(2, element.HeightRequest - textheight + 2, element.WidthRequest - 4,
textheight - 4);
descLayer.ContentsRect = descRec;
Control.Layer.AddSublayer(descLayer);
为什么不试试 autoLayout?您想要在原始图像上添加背景视图和两种类型的文本。 CALayer
可以达到你的效果,但它不能使用autoLayout,所以你需要使用硬代码(计算文本高度和图层位置)来构造它。你也说
I am unable to get the text to wrap. And I also don't know how to get the actual height of the tilteLayer so I can position the descLayer below it.
在图像的自定义渲染器中,由于此控件尚未渲染,因此其 Frame
和 HeightRequest
也是未知的。这样你就不会得到正确的框架,层也不会,所以文本不会显示。我认为最好的方法是使用 AutoLayout:
// Create a view to hold content just like your textLayer
UIView bgView = new UIView();
bgView.BackgroundColor = UIColor.FromRGBA(1, 1, 1, 0.25f);
bgView.TranslatesAutoresizingMaskIntoConstraints = false;
Control.AddSubview(bgView);
bgView.LeadingAnchor.ConstraintEqualTo(Control.LeadingAnchor).Active = true;
bgView.TopAnchor.ConstraintGreaterThanOrEqualTo(Control.TopAnchor).Active = true;
bgView.TrailingAnchor.ConstraintEqualTo(Control.TrailingAnchor).Active = true;
bgView.BottomAnchor.ConstraintEqualTo(Control.BottomAnchor).Active = true;
UILabel titleLabel = new UILabel();
bgView.AddSubview(titleLabel);
titleLabel.TranslatesAutoresizingMaskIntoConstraints = false;
// Set this property to 0, then your label will move to several lines if your text is too large.
titleLabel.Lines = 0;
titleLabel.Font = UIFont.SystemFontOfSize(14);
titleLabel.Text = Element.Item.Title;
titleLabel.LeadingAnchor.ConstraintEqualTo(bgView.LeadingAnchor).Active = true;
titleLabel.TopAnchor.ConstraintEqualTo(bgView.TopAnchor).Active = true;
titleLabel.TrailingAnchor.ConstraintEqualTo(bgView.TrailingAnchor).Active = true;
// This constraint will show the titleLabel's content at high priority. It means show the descLabel if the image has enough place.
titleLabel.SetContentHuggingPriority(249, UILayoutConstraintAxis.Vertical);
UILabel descLabel = new UILabel();
bgView.AddSubview(descLabel);
descLabel.TranslatesAutoresizingMaskIntoConstraints = false;
descLabel.Lines = 0;
descLabel.Text = Element.Item.Description;
descLabel.Font = UIFont.SystemFontOfSize(12);
descLabel.LeadingAnchor.ConstraintEqualTo(bgView.LeadingAnchor).Active = true;
descLabel.TopAnchor.ConstraintEqualTo(titleLabel.BottomAnchor).Active = true;
descLabel.TrailingAnchor.ConstraintEqualTo(bgView.TrailingAnchor).Active = true;
descLabel.BottomAnchor.ConstraintEqualTo(bgView.BottomAnchor).Active = true;
这样bgView会根据titleLabel和descLabel展开高度。最大高度将是原始图像的高度。此外,titleLabel 将根据其内容自动计算其大小。此外,如果房间允许,descLabel 将始终位于 titleLabel 下方。
您可以调整这些限制以满足您自己的要求。