我为iOS编写了一个自定义渲染器,以编程方式创建一个聊天气泡。主聊天气泡继承自ContentView,这样做是为了让我添加一个Label作为它的唯一孩子。在大多数情况下它运作良好但是只要有多行文本就会表现得非常奇怪,即文本溢出并且不尊重父母的界限(让我想起我十几岁的时候)。
当我用常规框架替换这个自定义控件时,一切似乎都运行良好。我通过覆盖Draw(CGRect)调用来计算所需的高度
代码在这里:
ppublic class ChatBubbleRenderer : VisualElementRenderer<ChatBubbleFrame>
{
public ChatBubbleRenderer()
{
this.ClipsToBounds = false;
}
public override void Draw(CGRect rect1)
{
var rect = Frame;
var currentContext = UIGraphics.GetCurrentContext();
var properRect = AdjustForThickness(rect);
HandleShapeDraw(currentContext, properRect);
}
protected RectangleF AdjustForThickness(CGRect rect)
{
var x = rect.X + Element.Padding.Left;
var y = rect.Y + Element.Padding.Top;
var width = rect.Width - ((Element.Padding.Left + (int)Element.StrokeWidth) * 2);
var height = rect.Height - ((Element.Padding.Top + (int)Element.StrokeWidth) * 2);
return new RectangleF((float)x, (float)y, (float)width, (float)height);
}
protected void HandleShapeDraw(CGContext currentContext, RectangleF rect)
{
var path = new CGPath();
var cr = (float)Element.CornerRadius;
var hl = (float)Element.HandleLength;
var x = rect.Left+hl;
var y = (float)rect.Top;
var startLeft = x;
var startTop = y;
var startRight = rect.Right - hl;
var startBottom = rect.Bottom ;
var centerX = x + cr;
var centerY = y + cr;
var width = (float)rect.Width - hl - hl;
var height = (float)rect.Height ;
if (Element.HandleIsBottomRight)
{
path.AddArc(centerX, centerY, cr, (float)Math.PI, (float)Math.PI * 3f / 2f, false);
x = startRight - cr;
//line to top right arc
path.AddLineToPoint(x, y);
//top right arc
centerX = x;
path.AddArc(centerX, centerY, cr, (float)Math.PI * 3f / 2f, 0, false);
x = x + cr;
//bring y down to top of triangle
y = y + height;
path.AddLineToPoint(x, y);
//chat handle
x = x + hl;
y = y + hl;
path.AddLineToPoint(x, y);
//to bottom left arc
x = startLeft + cr;
path.AddLineToPoint(x, y);
//bottom left arc
centerX = x;
centerY = y - cr;
path.AddArc(centerX, centerY, cr, (float)Math.PI / 2f, (float)Math.PI, false); //false to rotate clockwise
}
else
{
//line to top right arc
path.MoveToPoint(x, y);
x = startRight - cr;
path.AddLineToPoint(x, y);
//top right arc
centerX = x;
path.AddArc(centerX, centerY, cr, (float)Math.PI * 3f / 2f, 0, false);
//line to bottom right arc
x = x + cr;
y = y + height - cr;
path.AddLineToPoint(x, y);
//bottom right arc
centerX = x - cr;
centerY = y;
path.AddArc(centerX, centerY, cr, 0f, (float)Math.PI / 2f, false);
//line to bottom left arc
x = startLeft + cr;
y = y + cr;
path.AddLineToPoint(x, y);
//bottom left arc
centerX = x;
centerY = y - cr;
path.AddArc(centerX, centerY, cr, (float)Math.PI / 2f, (float)Math.PI, false); //false to rotate clockwise
//line to handle
x = startLeft;
y = startTop + hl;
path.AddLineToPoint(x, y);
x = x - hl;
y = startTop;
path.AddLineToPoint(x, y);
}
path.CloseSubpath();
HandleStandardDraw(currentContext, rect, () => currentContext.AddPath(path));
}
/// <summary>
/// A simple method for handling our drawing of the shape. This method is called differently for each type of shape
/// </summary>
/// <param name="currentContext">Current context.</param>
/// <param name="rect">Rect.</param>
/// <param name="createPathForShape">Create path for shape.</param>
/// <param name="lineWidth">Line width.</param>
protected virtual void HandleStandardDraw(CGContext currentContext, RectangleF rect, Action createPathForShape, float? lineWidth = null)
{
currentContext.SetLineWidth(lineWidth ?? Element.StrokeWidth);
currentContext.SetFillColor(Element.InnerColor.ToCGColor());
currentContext.SetStrokeColor(Element.StrokeColor.ToCGColor());
createPathForShape();
currentContext.DrawPath(CoreGraphics.CGPathDrawingMode.FillStroke);
}
}
聊天泡泡代码
public class ChatBubbleFrame : ContentView
{
public ChatBubbleFrame()
{
}
public static readonly BindableProperty HandleIsBottomRightProperty = BindableProperty.Create(
propertyName: "HandleIsBottomRight",
returnType: typeof(bool),
declaringType: typeof(ChatBubbleFrame),
defaultValue: true
);
public static readonly BindableProperty InnerColorProperty = BindableProperty.Create(
propertyName: "InnerColor",
returnType: typeof(Color),
declaringType: typeof(ChatBubbleFrame),
defaultValue: Color.Default
);
public static readonly BindableProperty HandleLengthProperty = BindableProperty.Create(
propertyName: "HandleLength",
returnType: typeof(float),
declaringType: typeof(ChatBubbleFrame),
defaultValue: 2f
);
public static readonly BindableProperty StrokeColorProperty = BindableProperty.Create(
propertyName: "StrokeColor",
returnType: typeof(Color),
declaringType: typeof(ChatBubbleFrame),
defaultValue: Color.Default
);
public static readonly BindableProperty StrokeWidthProperty = BindableProperty.Create(
propertyName: "StrokeWidth",
returnType: typeof(float),
declaringType: typeof(ChatBubbleFrame),
defaultValue: 1f
);
public static readonly BindableProperty CornerRadiusProperty = BindableProperty.Create(
propertyName: "CornerRadius",
returnType: typeof(float),
declaringType: typeof(ChatBubbleFrame),
defaultValue: 0f
);
public bool HandleIsBottomRight
{
get { return (bool)GetValue(HandleIsBottomRightProperty); }
set { SetValue(HandleIsBottomRightProperty, value); }
}
public float HandleLength
{
get { return (float)GetValue(HandleLengthProperty); }
set { SetValue(HandleLengthProperty, value); }
}
public Color StrokeColor
{
get { return (Color)GetValue(StrokeColorProperty); }
set { SetValue(StrokeColorProperty, value); }
}
public Color InnerColor
{
get { return (Color)GetValue(InnerColorProperty); }
set { SetValue(InnerColorProperty, value); }
}
public float StrokeWidth
{
get { return (float)GetValue(StrokeWidthProperty); }
set { SetValue(StrokeWidthProperty, value); }
}
public float CornerRadius
{
get
{
return (float)GetValue(CornerRadiusProperty);
}
set
{
SetValue(CornerRadiusProperty, value);
}
}
}
&#13;
Xaml片段
<controls:ChatBubbleFrame x:Name="OtherUserBubble"
HandleIsBottomRight="False"
StrokeColor="{StaticResource Color13}"
InnerColor="White"
StrokeWidth="1"
CornerRadius="10"
HandleLength="7"
HorizontalOptions="FillAndExpand"
VerticalOptions="StartAndExpand"
Padding="-1,10,10,10"
Margin="35,0,10,0"
Grid.Column="0">
<StackLayout Margin="17,10,12,18">
<Label Text="{Binding Entity.CommentText }"
Style="{StaticResource Typo23}"
LineBreakMode="WordWrap"
Margin="0,6,10,0" />
</StackLayout>
</controls:ChatBubbleFrame>
&#13;
良好消息泡泡和可怕消息泡泡的屏幕截图