Reputation: 18351
I'm trying to create a UILabel
with padding in my Xamarin.iOS app. The most popular solution in native Objective-C apps is overriding drawTextInRect
:
- (void)drawTextInRect:(CGRect)rect {
UIEdgeInsets insets = {0, 5, 0, 5};
return [super drawTextInRect:UIEdgeInsetsInsetRect(rect, insets)];
}
As simple as this seems, I can't quite figure out how to translate it to C#. Here's my best stab at it:
internal class PaddedLabel : UILabel
{
public UIEdgeInsets Insets { get; set; }
public override void DrawText(RectangleF rect)
{
var padded = new RectangleF(rect.X + Insets.Left, rect.Y, rext.Width + Insets.Left + Insets.Right, rect.Height);
base.DrawText(padded);
}
}
This does seem to move the label's text, but it doesn't resize the label.
I think the main issue is that I can't find the Xamarin equivalent of UIEdgeInsetsInsetRect
.
Any suggestions?
Upvotes: 12
Views: 11414
Reputation: 43
poupou's solution marked as the best answer doesn't work. I found another way to add padding to label.
public class PaddedLabel : UILabel
{
public PaddedLabel(IntPtr intPtr) : base(intPtr)
{
TextAlignment = UITextAlignment.Center;
}
public override CGSize IntrinsicContentSize
{
get
{
var size = base.IntrinsicContentSize;
return new CGSize(size + 16, size);
}
}
}
Upvotes: 0
Reputation: 583
The correct way to do this seems to have slightly changed since the original answer was given, and it took me awhile to figure out the new correct syntax. Here it is for anyone else who stumbles across this. This code would put padding of 5 on both the left and right sides of the view. This is in Xamarin.iOS
public override void DrawText(CGRect rect)
{
rect.X = 5;
rect.Width = rect.Width - 10; // or whatever padding settings you want
base.DrawText(AlignmentRectInsets.InsetRect(rect));
}
Upvotes: 0
Reputation: 1622
You have to override both DrawText
and TextRectForBounds.
If you don't override TextRectForBounds
, the text will be clipped.
Actually, you override this method to compensate the space which is occupied by padding and ask iOS to draw the text in a bigger rectangle.
public partial class LabelWithBorder
: UILabel
{
private UIEdgeInsets EdgeInsets = new UIEdgeInsets(5, 5, 5, 5);
private UIEdgeInsets InverseEdgeInsets = new UIEdgeInsets(-5, -5, -5, -5);
public LabelWithBorder(IntPtr handle) : base(handle)
{
}
public override CoreGraphics.CGRect TextRectForBounds(CoreGraphics.CGRect bounds, nint numberOfLines)
{
var textRect = base.TextRectForBounds(EdgeInsets.InsetRect(bounds), numberOfLines);
return InverseEdgeInsets.InsetRect(textRect);
}
public override void DrawText(CoreGraphics.CGRect rect)
{
base.DrawText(EdgeInsets.InsetRect(rect));
}
}
Upvotes: 7
Reputation: 5131
Rather than overriding DrawText() in the subclass of UILabel, override it's intrinsic content size. This way auto-layout takes the padding into consideration. For example here's my derived class of UILabel:
public class PaddedLabel : UILabel
{
private readonly float _top;
private readonly float _left;
private readonly float _right;
private readonly float _bottom;
public PaddedLabel(float top, float left, float right, float bottom)
{
_top = top;
_left = left;
_right = right;
_bottom = bottom;
}
public override CGSize IntrinsicContentSize => new CGSize(
base.IntrinsicContentSize.Width + _left + _right,
base.IntrinsicContentSize.Height + _top + _bottom
);
}
Upvotes: 3
Reputation: 149
I have created a generic Padding UIView class that wraps any IOS UI element that is derived from UIView.
Basically it nests the desired UIView into another view and takes care of all the padding work.
usage:
var myPaddedView = new PaddedUIView<UILabel>();
myPaddedView.Frame = TheActualFrame;
myPaddedView.Padding = 15f
myPaddedView.NestedView.Text = "Hello padded world"; // all the label Properties are available without side effects
Here is the class:
public class PaddedUIView<T>: UIView where T : UIView, new()
{
private float _padding;
private T _nestedView;
public PaddedUIView()
{
Initialize();
}
public PaddedUIView(RectangleF bounds)
: base(bounds)
{
Initialize();
}
void Initialize()
{
if(_nestedView == null)
{
_nestedView = new T();
this.AddSubview(_nestedView);
}
_nestedView.Frame = new RectangleF(_padding,_padding,Frame.Width - 2 * _padding, Frame.Height - 2 * _padding);
}
public T NestedView
{
get { return _nestedView; }
}
public float Padding
{
get { return _padding; }
set { if(value != _padding) { _padding = value; Initialize(); }}
}
public override RectangleF Frame
{
get { return base.Frame; }
set { base.Frame = value; Initialize(); }
}
}
Upvotes: 1
Reputation: 43553
The C# equivalent of the ObjC function UIEdgeInsetsInsetRect
is a instance method of UIEdgeInsets
named InsetRect
and it's not identical to your RectangleF
calculations (which is likely your problem).
To use it you can do:
public override void DrawText(RectangleF rect)
{
base.DrawText (Insets.InsetRect (rect));
}
Upvotes: 18