ios - هامش نص UILabel





cocoa-touch uikit (25)


إصدار سريع من إجابة Steel Recycled + intrinsizeContentSize() .

وهو يدعم نمطًا أكثر تقليدية لتعيين إدخالات لكائنات العرض الأخرى التي تحتوي على أدوات داخلية أثناء قدرتها على تعيين إدخالات في Interface Builder ، بمعنى أنه يتم تعيين الإضافات بطريقة برمجية:

label.inset = UIEdgeInsetsMake(0, 0, 5, 0)

واسمحوا لي أن أعرف ما إذا كان هناك أي أخطاء.

سويفت 3

@IBDesignable class InsetLabel: UILabel {
    @IBInspectable var topInset: CGFloat = 0.0
    @IBInspectable var leftInset: CGFloat = 0.0
    @IBInspectable var bottomInset: CGFloat = 0.0
    @IBInspectable var rightInset: CGFloat = 0.0

    var insets: UIEdgeInsets {
        get {
            return UIEdgeInsetsMake(topInset, leftInset, bottomInset, rightInset)
        }
        set {
            topInset = newValue.top
            leftInset = newValue.left
            bottomInset = newValue.bottom
            rightInset = newValue.right
        }
    }

    override func drawText(in rect: CGRect) {
        super.drawText(in: UIEdgeInsetsInsetRect(rect, insets))
    }

    override func sizeThatFits(_ size: CGSize) -> CGSize {
        var adjSize = super.sizeThatFits(size)
        adjSize.width += leftInset + rightInset
        adjSize.height += topInset + bottomInset

        return adjSize
    }

    override var intrinsicContentSize: CGSize {
        var contentSize = super.intrinsicContentSize
        contentSize.width += leftInset + rightInset
        contentSize.height += topInset + bottomInset

        return contentSize
    }
}

سويفت 2.2

@IBDesignable class InsetLabel: UILabel {
    @IBInspectable var topInset: CGFloat = 0.0
    @IBInspectable var leftInset: CGFloat = 0.0
    @IBInspectable var bottomInset: CGFloat = 0.0
    @IBInspectable var rightInset: CGFloat = 0.0

    var insets: UIEdgeInsets {
        get {
            return UIEdgeInsetsMake(topInset, leftInset, bottomInset, rightInset)
        }
        set {
            topInset = newValue.top
            leftInset = newValue.left
            bottomInset = newValue.bottom
            rightInset = newValue.right
        }
    }

    override func drawTextInRect(rect: CGRect) {
        super.drawTextInRect(UIEdgeInsetsInsetRect(rect, insets))
    }

    override func sizeThatFits(size: CGSize) -> CGSize {
        var adjSize = super.sizeThatFits(size)
        adjSize.width += leftInset + rightInset
        adjSize.height += topInset + bottomInset

        return adjSize
    }

    override func intrinsicContentSize() -> CGSize {
        var contentSize = super.intrinsicContentSize()
        contentSize.width += leftInset + rightInset
        contentSize.height += topInset + bottomInset

        return contentSize
    }
}

أنا أتطلع إلى تعيين UILabel / UILabel الأيسر من UILabel ولا يمكن العثور على طريقة للقيام بذلك. تحتوي العلامة على مجموعة خلفية ، لذا لن يؤدي تغيير الأصل إلا إلى القيام بالخدعة. سيكون مثاليًا لإدراج النص بمقدار 10 10px على الجانب الأيسر.




الإصدار المتوافق مع Swift 3 & AutoLayout :

class InsetLabel: UILabel {

    var insets = UIEdgeInsets()

    convenience init(insets: UIEdgeInsets) {
        self.init(frame: CGRect.zero)
        self.insets = insets
    }

    convenience init(dx: CGFloat, dy: CGFloat) {
        let insets = UIEdgeInsets(top: dy, left: dx, bottom: dy, right: dx)
        self.init(insets: insets)
    }

    override func drawText(in rect: CGRect) {
        super.drawText(in: UIEdgeInsetsInsetRect(rect, insets))
    }

    override var intrinsicContentSize: CGSize  {
        var size = super.intrinsicContentSize
        size.width += insets.left + insets.right
        size.height += insets.top + insets.bottom
        return size
    }
}



وIBDesignable التي تجعلها تعمل مع Interface Builder

@IBDesignable
class PaddedLabel: UILabel {

    @IBInspectable var inset:CGSize = CGSize(width: 0, height: 0)

    var padding: UIEdgeInsets {
        var hasText:Bool = false
        if let t = text?.length where t > 0 {
            hasText = true
        }
        else if let t = attributedText?.length where t > 0 {
            hasText = true
        }

        return hasText ? UIEdgeInsets(top: inset.height, left: inset.width, bottom: inset.height, right: inset.width) : UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
    }

    override func drawTextInRect(rect: CGRect) {
        super.drawTextInRect(UIEdgeInsetsInsetRect(rect, padding))
    }

    override func intrinsicContentSize() -> CGSize {
        let superContentSize = super.intrinsicContentSize()
        let p = padding
        let width = superContentSize.width + p.left + p.right
        let heigth = superContentSize.height + p.top + p.bottom
        return CGSize(width: width, height: heigth)
    }

    override func sizeThatFits(size: CGSize) -> CGSize {
        let superSizeThatFits = super.sizeThatFits(size)
        let p = padding
        let width = superSizeThatFits.width + p.left + p.right
        let heigth = superSizeThatFits.height + p.top + p.bottom
        return CGSize(width: width, height: heigth)
    }
}



هذا يعمل بشكل صحيح مع تسميات متعددة الأسطر:

class PaddedLabel: UILabel {
    var verticalPadding: CGFloat = 0
    var horizontalPadding: CGFloat = 0

    override func drawText(in rect: CGRect) {
        let insets = UIEdgeInsets(top: verticalPadding, left: horizontalPadding, bottom: verticalPadding, right: horizontalPadding)
        super.drawText(in: UIEdgeInsetsInsetRect(rect, insets))
    }

    override var intrinsicContentSize: CGSize {
        get {
            let textWidth = super.intrinsicContentSize.width - horizontalPadding * 2
            let textHeight = sizeThatFits(CGSize(width: textWidth, height: .greatestFiniteMagnitude)).height
            let width = textWidth + horizontalPadding * 2
            let height = textHeight + verticalPadding * 2
            return CGSize(width: frame.width, height: height)
        }
    }
}



ربما يمكنك إعطاء هذا الرمز محاولة

CGRect frame = btn.titleLabel.frame;
int indent = 20;
int inset = 20;
[btn.titleLabel setFrame:CGRectMake(frame.origin.x+inset,frame.origin.y,frame.size.width+indent,frame.size.height)];



أنا حل هذا عن طريق تصنيف فئة فرعية UILabel وتجاوز drawTextInRect: مثل هذا:

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

ما يعادل في Swift 3.1:

override func drawText(in rect: CGRect) {
    let insets = UIEdgeInsets.init(top: 0, left: 5, bottom: 0, right: 5)
    super.drawText(in: UIEdgeInsetsInsetRect(rect, insets))
}

كما قد تكون قد تجمعت ، فهذا تكيّف لإجابة tc . له ميزتان على ذلك:

  1. ليس هناك حاجة إلى تشغيله عن طريق إرسال رسالة sizeToFit
  2. فإنه يترك إطار التسمية بمفرده - سهل إذا كانت العلامة الخاصة بك تحتوي على خلفية ولا تريد أن يتقلص ذلك



أعتقد أن طبقة UILabel ليس لديها طريقة لتحديد الهامش. لماذا لا تحدد وضع التسمية في المكان المطلوب؟

انظر أدناه الكود:

UILabel *label = [[UILabel alloc] init];
label.text = @"This is label";
label.frame = CGRectMake(0,0,100,100);

إذا كنت تستخدم أداة إنشاء الواجهة ، فيمكنك فقط وضع التصنيف من خلال اتباع ما يلي:

yourLabel.frame = CGRectMake(0,0,100,100);



أفضل أسلوب لإضافة الحشو إلى UILabel هو فئة فرعية UILabel وإضافة خاصية edgeInsets. بعد ذلك ، تضبط الإعدادات المطلوبة وتوضع العلامة وفقًا لذلك.

OSLabel.h

#import <UIKit/UIKit.h>

@interface OSLabel : UILabel

@property (nonatomic, assign) UIEdgeInsets edgeInsets;

@end

OSLabel.m

#import "OSLabel.h"

@implementation OSLabel

- (id)initWithFrame:(CGRect)frame{
    self = [super initWithFrame:frame];
    if (self) {
        self.edgeInsets = UIEdgeInsetsMake(0, 0, 0, 0);
    }
    return self;
}

- (void)drawTextInRect:(CGRect)rect {
    [super drawTextInRect:UIEdgeInsetsInsetRect(rect, self.edgeInsets)];
}

- (CGSize)intrinsicContentSize
{
    CGSize size = [super intrinsicContentSize];
    size.width  += self.edgeInsets.left + self.edgeInsets.right;
    size.height += self.edgeInsets.top + self.edgeInsets.bottom;
    return size;
}

@end



هذه هي أسهل طريقة وجدت. وهي تعمل مثل سحر بالنسبة لي.

UIView *titleSection = [[UIView alloc] initWithFrame:CGRectMake(0, 0, screenWidth, 100)];
[titleSection addSubview:titleSection];

UILabel *label = [[UILabel alloc] initWithFrame:CGRectInset(titleSection.frame, PADDING, 0)];
[titleSection addSubview:label];



بدلا من UILabel ربما يستخدم github.com/mattt/TTTAttributedLabel

BITAttributedLabel *label = [BITAttributedLabel new];
label.font = font;
label.text = @"hello";
label.textInsets = UIEdgeInsetsMake(10, 10, 10, 10);
[label sizeToFit];



ما عليك سوى إضافة مسافات إلى اليسار إذا كان سطرًا واحدًا ، فسيحتوي أكثر من سطر واحد على 0 حشوة مرة أخرى.

[self.myLabel setText:[NSString stringWithFormat:@"   %@", self.myShortString]];



الكثير من الإجابات تفتقد تجاوز sizeThatFits. باستخدام هذا الفئة الفرعية يمكنك فقط إنشاء التسمية ، وتعيين الحشو ، ثم قول label.SizeToFit () و voila.

import UIKit

class UILabelEx : UILabel
{
    var padding : UIEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)

    override func drawTextInRect(rect: CGRect) {

        super.drawTextInRect(UIEdgeInsetsInsetRect(rect, padding))
    }

    override func sizeThatFits(size: CGSize) -> CGSize
    {

        var adjSize = super.sizeThatFits(size)
        adjSize.width += padding.left + padding.right
        adjSize.height += padding.top + padding.bottom

        return adjSize
    }
}



لمستخدمي Xamarin (باستخدام واجهة برمجة التطبيقات الموحدة):

class UIMarginLabel : UILabel
{
    public UIMarginLabel()
    {
    }

    public UIMarginLabel( RectangleF frame ) : base( frame )
    {
    }

    public UIEdgeInsets Insets { get; set; }

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

وبالنسبة لأولئك الذين يستخدمون واجهة برمجة تطبيقات MonoTouch الأصلية:

public class UIMarginLabel : UILabel
{
    public UIEdgeInsets Insets { get; set; }

    public UIMarginLabel() : base()
    {
        Insets = new UIEdgeInsets(0, 0, 0, 0);
    }
    public UIMarginLabel(RectangleF frame) : base(frame)
    {
        Insets = new UIEdgeInsets(0, 0, 0, 0);
    }

    public override void DrawText(RectangleF frame)
    {
        base.DrawText(new RectangleF(
            frame.X + Insets.Left,
            frame.Y + Insets.Top,
            frame.Width - Insets.Left - Insets.Right,
            frame.Height - Insets.Top - Insets.Bottom));
    }
}



يمكنك أيضًا حل هذه المشكلة من خلال تهيئة UILabel باستخدام إطار مخصص.

    CGRect initialFrame = CGRectMake(0, 0, 100, 100);
    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0, 10, 0, 0);
    CGRect paddedFrame = UIEdgeInsetsInsetRect(initialFrame, contentInsets);

    self.label = [[UILabel alloc] initWithFrame:paddedFrame];

نود ل CGRect الحيل .




للتخلص من الحشو الرأسي لملصق سطر واحد قمت به:

// I have a category method setFrameHeight; you'll likely need to modify the frame.
[label setFrameHeight:font.pointSize];

أو بدون الفئة ، استخدم:

CGRect frame = label.frame;
frame.size.height = font.pointSize;
label.frame = frame;



للتوسع في الإجابة المقدمة من برودي روبرتسون ، يمكنك إضافة بتات IB Designable. هذا يعني أنه يمكنك ضبط الملصق من داخل Storyboard.

في الخاص بك UILabel subclassed القيام به

#import <UIKit/UIKit.h>

IB_DESIGNABLE

@interface insetLabel : UILabel

@property (nonatomic, assign) IBInspectable CGFloat leftEdge;
@property (nonatomic, assign) IBInspectable CGFloat rightEdge;
@property (nonatomic, assign) IBInspectable CGFloat topEdge;
@property (nonatomic, assign) IBInspectable CGFloat bottomEdge;

@property (nonatomic, assign) UIEdgeInsets edgeInsets;

@end

ثم افعل

#import "insetLabel.h"

@implementation insetLabel

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self)
    {
        self.edgeInsets = UIEdgeInsetsMake(self.topEdge, self.leftEdge, self.bottomEdge, self.rightEdge);
    }
    return self;
}

- (void)drawTextInRect:(CGRect)rect
{
    self.edgeInsets = UIEdgeInsetsMake(self.topEdge, self.leftEdge, self.bottomEdge, self.rightEdge);

    [super drawTextInRect:UIEdgeInsetsInsetRect(rect, self.edgeInsets)];
}

- (CGSize)intrinsicContentSize
{
    CGSize size = [super intrinsicContentSize];
    size.width  += self.edgeInsets.left + self.edgeInsets.right;
    size.height += self.edgeInsets.top + self.edgeInsets.bottom;
    return size;
}

@end

تصحيح

ربما ينبغي عليك إضافة طريقة تعيين لـ edgeInsets.




مع Swift 3 ، يمكنك الحصول على التأثير المطلوب عن طريق إنشاء فئة فرعية من UILabel . في هذه الفئة الفرعية ، ستحتاج إلى إضافة خاصية UIEdgeInsets مع UIEdgeInsets المطلوبة وتجاوز drawText(in:) طريقة drawText(in:) ، خاصية intrinsicContentSize (من أجل رمز تخطيط تلقائي) و / أو sizeThatFits(_:) (لرمز Springs & Struts).

import UIKit

class PaddingLabel: UILabel {

    let padding: UIEdgeInsets

    // Create a new PaddingLabel instance programamtically with the desired insets
    required init(padding: UIEdgeInsets = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 10)) {
        self.padding = padding
        super.init(frame: CGRect.zero)
    }

    // Create a new PaddingLabel instance programamtically with default insets
    override init(frame: CGRect) {
        padding = UIEdgeInsets.zero // set desired insets value according to your needs
        super.init(frame: frame)
    }

    // Create a new PaddingLabel instance from Storyboard with default insets
    required init?(coder aDecoder: NSCoder) {
        padding = UIEdgeInsets.zero // set desired insets value according to your needs
        super.init(coder: aDecoder)
    }

    override func drawText(in rect: CGRect) {
        super.drawText(in: UIEdgeInsetsInsetRect(rect, padding))
    }

    // Override `intrinsicContentSize` property for Auto layout code
    override var intrinsicContentSize: CGSize {
        let superContentSize = super.intrinsicContentSize
        let width = superContentSize.width + padding.left + padding.right
        let heigth = superContentSize.height + padding.top + padding.bottom
        return CGSize(width: width, height: heigth)
    }

    // Override `sizeThatFits(_:)` method for Springs & Struts code
    override func sizeThatFits(_ size: CGSize) -> CGSize {
        let superSizeThatFits = super.sizeThatFits(size)
        let width = superSizeThatFits.width + padding.left + padding.right
        let heigth = superSizeThatFits.height + padding.top + padding.bottom
        return CGSize(width: width, height: heigth)
    }

}

يوضح المثال التالي كيفية استخدام مثيلات PaddingLabel في PaddingLabel :

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var storyboardAutoLayoutLabel: PaddingLabel!
    let autoLayoutLabel = PaddingLabel(padding: UIEdgeInsets(top: 20, left: 40, bottom: 20, right: 40))
    let springsAndStructsLabel = PaddingLabel(frame: CGRect.zero)
    var textToDisplay = "Lorem ipsum dolor sit er elit lamet."

    override func viewDidLoad() {
        super.viewDidLoad()

        // Set autoLayoutLabel
        autoLayoutLabel.text = textToDisplay
        autoLayoutLabel.backgroundColor = .red
        autoLayoutLabel.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(autoLayoutLabel)
        autoLayoutLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 30).isActive = true
        autoLayoutLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true

        // Set springsAndStructsLabel
        springsAndStructsLabel.text = textToDisplay
        springsAndStructsLabel.backgroundColor = .green
        view.addSubview(springsAndStructsLabel)
        springsAndStructsLabel.frame.origin = CGPoint(x: 30, y: 90)
        springsAndStructsLabel.sizeToFit()

        // Set storyboardAutoLayoutLabel
        storyboardAutoLayoutLabel.text = textToDisplay
        storyboardAutoLayoutLabel.backgroundColor = .blue
    }

    // Link this IBAction to a UIButton or a UIBarButtonItem in Storyboard
    @IBAction func updateLabelText(_ sender: Any) {
        textToDisplay = textToDisplay == "Lorem ipsum dolor sit er elit lamet." ? "Lorem ipsum." : "Lorem ipsum dolor sit er elit lamet."

        // autoLayoutLabel
        autoLayoutLabel.text = textToDisplay

        // springsAndStructsLabel
        springsAndStructsLabel.text = textToDisplay
        springsAndStructsLabel.sizeToFit()

        // storyboardAutoLayoutLabel
        storyboardAutoLayoutLabel.text = textToDisplay
    }

}



إذا كنت لا ترغب في استخدام عرض أصل إضافي لتعيين الخلفية ، يمكنك تصنيف فئة فرعية UILabel وتجاوز textRectForBounds:limitedToNumberOfLines: سأقوم بإضافة خاصية textEdgeInsets أو ما شابه ، ثم القيام بذلك

- (CGRect)textRectForBounds:(CGRect)bounds limitedToNumberOfLines:(NSInteger)numberOfLines
{
  return [super textRectForBounds:UIEdgeInsetsInsetRect(bounds,textEdgeInsets) limitedToNumberOfLines:numberOfLines];
}

للحصول على متانة ، قد ترغب أيضًا في الاتصال بـ [self setNeedsDisplay] في setTextEdgeInsets: ، لكنني عادة لا أزعجك.




دون subclassing وكل ذلك الجاز .. فعلت ذلك بشكل حيوي:

[cell.textLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
[cell.textLabel constraintTrailingEqualTo:cell.contentView constant:-100];

الجزء القيد هو مجرد رمز سكر بسيط (لدينا نفس الأساليب لإضافة حشوة من أعلى / أسفل / يسار / يمين) .. سأقوم بفتح المصدر المجمع بأكمله إذا حصلت على ما يكفي من الحب هنا:

- (id)constraintTrailingEqualTo:(UIView *)toView constant:(CGFloat)constant
{
    NSLayoutConstraint *cn = [NSLayoutConstraint constraintWithItem:self
                                                          attribute:NSLayoutAttributeTrailing
                                                          relatedBy:NSLayoutRelationEqual
                                                             toItem:toView
                                                          attribute:NSLayoutAttributeTrailing
                                                         multiplier:1 constant:constant];

    [toView addConstraint:cn];
    return self;
}

(لاحظ أنني فعلت هذا في سياق

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath;

قد تضطر إلى استدعاء [self setNeedsLayout]; اعتمادا على السياق الخاص بك.




انتهى بي الأمر فقط بإضافة بعض المسافات إلى النص:

self.titleLabel.text = [NSString stringWithFormat:@"    %@", self.titleLabel.text];

قبيحة لكنها فعالة ، ولا تتطلب فئة فرعية.

يمكنك تجربة "\ t" أيضًا. للحصول على حل عام ، يرجى الرجوع إلى الإجابة المقبولة




بالنسبة للنص متعدد الأسطر ، يمكن تعيين الهامش الأيسر واليمين باستخدام NSAttributedString.

NSMutableParagraphStyle *style =  [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
style.alignment = NSTextAlignmentJustified;
style.firstLineHeadIndent = 10.0f;
style.headIndent = 10.0f;
style.tailIndent = -10.0f;   

NSAttributedString *attrText = [[NSAttributedString alloc] initWithString:title attributes:@{ NSParagraphStyleAttributeName : style}];  

UILabel * label = [[UILabel alloc] initWithFrame:someFrame];
label.numberOfLines = 0;
label.attributedText = attrText;



الكثير من هذه الإجابات معقدة. في بعض الحالات ، هذا ضروري. ومع ذلك ، إذا كنت تقرأ هذا ، فإن التسمية لا تحتوي على هامش يسار / يمين ، وتريد فقط القليل من المساحة ، وهنا الحل الكامل:

الخطوة 1: إضافة مسافات في النهاية (حرفيًا ، اضغط على مفتاح المسافة عدة مرات)

الخطوة 2: قم بتعيين محاذاة النص الخاصة بالتسمية إلى المنتصف

فعله




subclassing قليلا مرهقة لهذه الحالة البسيطة. البديل هو ببساطة إضافة UILabel مع عدم تعيين الخلفية إلى UIView مع مجموعة الخلفية. عيّن علامة x إلى 10 وجعل حجم العرض الخارجي 10 بكسل أكبر من الملصق.




Xcode 6.1.1 حل سريع باستخدام امتداد.

قد يكون اسم الملف شيئًا مثل "UILabel + AddInsetMargin.swift":

import UIKit

extension UILabel
{
    public override func drawRect(rect: CGRect)
    {
        self.drawTextInRect(UIEdgeInsetsInsetRect(rect, UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5)))
    }
}



للمبرمجين سويفت :

هذا سوف يقوم بكل شيء من أجلك ، فقط ضع هذه في فئة وحدة التحكم في العرض لديك وقم بتطبيق UITextFieldDelegate على جهاز العرض الخاص بك وقم بتعيين مندوب UITextFieldDelegate على self

textField.delegate = self // Setting delegate of your UITextField to self

تطبيق أساليب رد الاتصال المفوض:

func textFieldDidBeginEditing(textField: UITextField) {
    animateViewMoving(true, moveValue: 100)
}

func textFieldDidEndEditing(textField: UITextField) {
    animateViewMoving(false, moveValue: 100)
}

// Lifting the view up
func animateViewMoving (up:Bool, moveValue :CGFloat){
    let movementDuration:NSTimeInterval = 0.3
    let movement:CGFloat = ( up ? -moveValue : moveValue)
    UIView.beginAnimations( "animateView", context: nil)
    UIView.setAnimationBeginsFromCurrentState(true)
    UIView.setAnimationDuration(movementDuration )
    self.view.frame = CGRectOffset(self.view.frame, 0,  movement)
    UIView.commitAnimations()
}




ios cocoa-touch uikit uilabel