在Xamarin.iOS中如何设置UILabel的内边距?

12

我正在尝试在我的Xamarin.iOS应用程序中创建带有填充的UILabel。在本机Objective-C应用程序中,最流行的解决方案是覆盖drawTextInRect

- (void)drawTextInRect:(CGRect)rect {
    UIEdgeInsets insets = {0, 5, 0, 5};
    return [super drawTextInRect:UIEdgeInsetsInsetRect(rect, insets)];
}

虽然看起来很简单,但我还是不能完全想清楚如何将其翻译成C#。以下是我的最佳尝试:

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

这似乎确实移动了标签的文本,但它没有调整标签的大小。

我认为主要问题是我找不到Xamarin版的UIEdgeInsetsInsetRect

有任何建议吗?

6个回答

18

在C#中,UIEdgeInsetsInsetRect函数的等价物是UIEdgeInsets实例方法InsetRect,它与您的RectangleF计算不完全相同(这很可能是您的问题)。

要使用它,您可以执行以下操作:

public override void DrawText(RectangleF rect)
{
    base.DrawText (Insets.InsetRect (rect));
}

谢谢!这似乎是Objective-C版本的正确翻译。它按预期将文本向右移动,但文本被剪裁到右侧。换句话说,UILabel没有调整大小以适应插图。不过这可能是一个单独的问题。 - Josh Earl
那段代码只改变了绘图,所以 UILabel 不知道插入(并且不会改变它的行为)。 - poupou
有道理。您有什么建议,我应该查看哪些内容来考虑插图在确定标签宽度时的影响?如果可能的话,我希望它可以动态调整大小。 - Josh Earl
我不确定你想要什么确切的结果 - 但是在SO上有很多类似的问题,例如https://dev59.com/_1nUa4cB1Zd3GeqPc69o,你可能想要查看(并转换为C#)。如果没有符合您需求的内容,请提出另一个更精确的问题(例如图片)以寻求帮助。 - poupou
1
谢谢--我发布了一个带有屏幕截图的跟进问题:https://dev59.com/EmEi5IYBdhLWcg3wjs5j - Josh Earl
这似乎已经过时了,看看我下面的回答。 - jnel899

7
你需要重写 both DrawTextTextRectForBounds 方法。 如果不重写 TextRectForBounds 方法,文本将被剪裁。 实际上,你重写此方法是为了补偿填充占用的空间,并要求 iOS 在更大的矩形中绘制文本。
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));
    }
}

这个方案运作得很好,只是我不得不添加一个接受CGRect并将其传递给该类型基础构造函数的构造函数。 - Jim Wilcox

2

不要在UILabel的子类中覆盖DrawText(),而是覆盖它的内在内容大小。这样自动布局会考虑填充。例如,这是我的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
    );
}

1

我创建了一个通用的Padding UIView类,它包装了任何派生自UIView的IOS UI元素。

基本上它把所需的UIView嵌套到另一个视图中,并负责所有填充工作。

使用方法:

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

这里是类:
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(); }
    }
}

公共覆盖矩形F框架,此方法未解决。 - Signcodeindie

0

自从原始答案发布以来,正确的方法似乎略有改变,我花了一些时间才弄清楚新的正确语法。以下是正确的代码,供其他遇到同样问题的人参考。此代码将在视图的左右两侧添加5个填充。这是在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));
}

0
poupou的解决方案被标记为最佳答案,但实际上并不起作用。我找到了另一种方法来给标签添加填充。
    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);
            }
        }
    }

1
你的答案可以通过提供额外的支持信息来改善。请[编辑]以添加进一步的细节,例如引用或文档,以便其他人可以确认您的答案是否正确。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接