UITextFieldのテキストインセット?


回答:


628

オーバーライド-textRectForBounds:は、プレースホルダーテキストのインセットのみを変更します。編集可能なテキストのインセットを変更するには、オーバーライドする必要もあります-editingRectForBounds:

// placeholder position
- (CGRect)textRectForBounds:(CGRect)bounds {
     return CGRectInset(bounds, 10, 10);
}

// text position
- (CGRect)editingRectForBounds:(CGRect)bounds {
     return CGRectInset(bounds, 10, 10);
}

10
この解決策はうまくいきましたが、CGRectInset(bounds、9、0)の戻り値を使用しました。また、この値をtextRectForBounds、editingRectForBounds、およびplaceholderRectForBoundsに設定する必要がありました。
RyJ

2
このソリューションは、clearButtonではうまく機能しません。TextFieldオーバーレイボタン内のテキスト。
Piotr

上記のメソッドをオーバーライドすると、UITextField内にある場合、スクロールが遅くなりますUIScrollView
Bharat Dodeja 2013年

2
:ClearButton置くため - (CGRect)clearButtonRectForBounds:(CGRect)bounds { return CGRectMake(x, y, w, h); } :ここが見つかりstackoverflow.com/questions/5361369/...
MIROS

22
CGRectInset(bounds、10、10)を呼び出す前に、[super textRectForBounds:bounds]と[super editingRectForBounds:bounds]を呼び出すことをお勧めします。これにより、クリアボタンオーバーレイの問題が修正されます。
mrvincenzo 2013

294

私はそれを行うことができました:

myTextField.layer.sublayerTransform = CATransform3DMakeTranslation(5, 0, 0);

もちろん、QuartzCoreをインポートし、フレームワークをプロジェクトに追加することを忘れないでください。


38
創造性のための+1ですが、これは少し問題があります。テキストフィールド内の削除ボタンも移動します
Nikita

2
すべてのサブレイヤーの配列であるmyTextField.layer.sublayersを実行できます...そして、そのUIImageView <-Xが画像であると想定しています...または多分UIButton ...またはそれぞれをループして見てどちらが所属するサブビュー...しかしmyfield.layer.sublayerTransformすべてのサブレイヤので、Xボタンも同様に...移動
chuthan20

この解決策は私にはうまくいきません。左マージンと上マージンのみ設定でき、右マージンと下マージンは設定できません。UITextField右側のコンテンツと重なります。
Bharat Dodeja 2013年

2
これは、サブクラス化なしの最良のソリューションであり、画面に配置するために余分な不要なビューを必要としません。+1!
Rambatino 2014年

1
@この写真の右側にあるXボタンjeet.chanchawat .. developer.apple.com/library/content/documentation/...
chuthan20

169

左マージンだけが必要な場合は、これを試すことができます:

UItextField *textField = [[UITextField alloc] initWithFrame:...];
UIView *leftView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, textField.frame.size.height)];
leftView.backgroundColor = textField.backgroundColor;
textField.leftView = leftView;
textField.leftViewMode = UITextFieldViewModeAlways;

わたしにはできる。これがお役に立てば幸いです。


17
これは、インセットを取得するためだけにサブクラス化するよりもはるかに簡単で、左側に任意のビューを追加できます(rightViewを使用して右側に何かを配置することもできます)。受け入れられた答えよりも良い私見。
ケニーグラント

4
+1、サブクラス化なし、テキストフィールドプロパティ(「ハッキング」ではなく)で動作するように設計されています。
So Over It

3行目はleftView.backgroundColor = textField.backgroundColor;...そのすばらしい解決策以外に...感謝(:
Aviel Gross

azdevの答えほどエレガントではありませんが、一般的で単純なケースの優れたソリューションです!
レンブラントQ.アインシュタイン

1
これを必要とする単一のテキストボックスがない限り、サブクラス化を使用すると、この回答よりも大幅に時間を節約できます。
2015年

168

UITextFieldから派生したクラスで、少なくともこの2つのメソッドをオーバーライドします。

- (CGRect)textRectForBounds:(CGRect)bounds;
- (CGRect)editingRectForBounds:(CGRect)bounds;

追加コンテンツがない場合、これはこれと同じくらい簡単かもしれません:

return CGRectInset(bounds , 10, 10);

UITextFieldは、オーバーライドできるいくつかの位置決めメソッドを提供します。


2
はい、editingRectForBoundsをオーバーライドしない場合は、テキストフィールドの左上で編集するときにテキストが取得されます。-(CGRect)editingRectForBounds:(CGRect)bounds {return CGRectInset(bounds、10、10); }
Mark W

1
答えを編集して、editingRectForBoundsメソッドを次のように統合しました
14

5
これは私には恐ろしいハックのようです-あなたもオーバーライドする必要があります- (CGRect)borderRectForBounds:(CGRect)bounds; - (CGRect)placeholderRectForBounds:(CGRect)bounds; - (CGRect)clearButtonRectForBounds:(CGRect)bounds; - (CGRect)leftViewRectForBounds:(CGRect)bounds; - (CGRect)rightViewRectForBounds:(CGRect)bounds;
Zorayr

98

どの程度@IBInspectable@IBDesignable迅速なクラス。

@IBDesignable
class TextField: UITextField {
    @IBInspectable var insetX: CGFloat = 6 {
       didSet {
         layoutIfNeeded()
       }
    }
    @IBInspectable var insetY: CGFloat = 6 {
       didSet {
         layoutIfNeeded()
       }
    }

    // placeholder position
    override func textRectForBounds(bounds: CGRect) -> CGRect {
        return CGRectInset(bounds , insetX , insetY)
    }

    // text position
    override func editingRectForBounds(bounds: CGRect) -> CGRect {
        return CGRectInset(bounds , insetX , insetY)
    }
}

これはストーリーボードに表示されます。

ここに画像の説明を入力してください

アップデート-Swift 3

@IBDesignable
class TextField: UITextField {
    @IBInspectable var insetX: CGFloat = 0
    @IBInspectable var insetY: CGFloat = 0

    // placeholder position
    override func textRect(forBounds bounds: CGRect) -> CGRect {
        return bounds.insetBy(dx: insetX, dy: insetY)
    }

    // text position
    override func editingRect(forBounds bounds: CGRect) -> CGRect {
        return bounds.insetBy(dx: insetX, dy: insetY)
    }
}

1
Yへの影響は望ましくないことがわかりました。テキストの四角形を縮小するのではなく、フィールドのベースラインに向かって少しずつ動かします。実装を次のように調整しましたlet rect = CGRect(x: bounds.minX, y: bounds.minY + insetY, width: bounds.width, height: bounds.height) return CGRectInset(rect , insetX , 0)
Chris Wagner、

1
プレースホルダーを使用している場合もこれを追加します `override func placeholderRectForBounds(bounds:CGRect)-> CGRect {return CGRectInset(bounds、insetX、insetY)}`
RameshVel

奇妙なことに、これは(インセットをtextRect/に設定するeditingRect)、テキストが表示可能な四角形からオーバーフローするときのスクロールパフォーマンス(少なくともiOS 12)に影響します。15のインセットでは、スクロールも停止します。
Ixx

29

クリアボタンがある場合、承認された回答は機能しません。また、に電話をかけて、Appleが将来的に物事を変更するのを防ぐ必要もありsuperます。

したがって、テキストがクリアボタンと重ならないようにするために、super最初から「デフォルト」値を取得し、必要に応じて調整します。

このコードは、テキストフィールドの上下左右に10pxのインセットを追加します。

@interface InsetTextField : UITextField

@end


@implementation InsetTextField

// Placeholder position
- (CGRect)textRectForBounds:(CGRect)bounds {
    CGRect rect = [super textRectForBounds:bounds];
    UIEdgeInsets insets = UIEdgeInsetsMake(10, 10, 10, 0);

    return UIEdgeInsetsInsetRect(rect, insets);
}

// Text position
- (CGRect)editingRectForBounds:(CGRect)bounds {
    CGRect rect = [super editingRectForBounds:bounds];
    UIEdgeInsets insets = UIEdgeInsetsMake(10, 10, 10, 0);

    return UIEdgeInsetsInsetRect(rect, insets);
}

// Clear button position
- (CGRect)clearButtonRectForBounds:(CGRect)bounds {
    CGRect rect = [super clearButtonRectForBounds:bounds];

    return CGRectOffset(rect, -5, 0);
}

@end

注:UIEdgeInsetsMakeは、パラメーターをtopleftbottomrightの順序で受け取ります。


使用するtextRectForBounds:と、editingRectForBounds:メソッドなし clearButtonRectForBounds:のiOS 7+では、私のために働きました。
Stunner、2015年

clearButtonRectForBounds:クリアボタンを少し左に動かします。省略してもかまいません。テキストフィールドの背景が暗いため、クリアボタンの右側に少し余分なパディングが必要でした。
Chris Nolet、2015年

奇妙なことに、テキストが表示可能な四角形をオーバーフローするとき、これは(少なくともiOS 12では)スクロールパフォーマンスに影響します。15のインセットでは、スクロールも停止します。
Ixx

22

私はSwiftソリューションを提供すると思いました

import UIKit

class TextField: UITextField {
    let inset: CGFloat = 10

    // placeholder position
    override func textRectForBounds(bounds: CGRect) -> CGRect {
        return CGRectInset(bounds , inset , inset)
    }

    // text position
    override func editingRectForBounds(bounds: CGRect) -> CGRect {
        return CGRectInset(bounds , inset , inset)
    }

    override func placeholderRectForBounds(bounds: CGRect) -> CGRect {
        return CGRectInset(bounds, inset, inset) 
    }
}

Swift 3以上

import UIKit

class TextField: UITextField {
    let inset: CGFloat = 10

    // placeholder position
    override func textRect(forBounds: CGRect) -> CGRect {
        return forBounds.insetBy(dx: self.inset , dy: self.inset)
    }

    // text position
    override func editingRect(forBounds: CGRect) -> CGRect {
        return forBounds.insetBy(dx: self.inset , dy: self.inset)
    }

    override func placeholderRect(forBounds: CGRect) -> CGRect {
        return forBounds.insetBy(dx: self.inset, dy: self.inset)
    }
}

2
忘れないでください override func placeholderRectForBounds(bounds: CGRect) -> CGRect { return CGRectInset(bounds, inset, inset) }
Eugene Braginets

Swift 3では 'CGRect.insetBy()'メソッドを使用する必要があります
Den

1
少なくともiOS 11では、をオーバーライドするtextRectForBoundsと、プレースホルダーも影響を受けるため、プレースホルダーのオーバーライドを追加すると、プレースホルダーがさらに10ポイント挿入されます。それがあなたが探しているものである場合はnot、そうでない場合は注意することをお勧めします。
DesignatedNerd

奇妙なことに、テキストが表示可能な四角形をオーバーフローするとき、これは(少なくともiOS 12では)スクロールパフォーマンスに影響します。15のインセットでは、スクロールも停止します。
Ixx

14

使用textRectForBounds:は正しいアプローチです。これを自分のサブクラスにまとめたので、簡単に使用できますtextEdgeInsetsSSTextFieldを参照してください。


このアプローチは、cocoapodsを使用してSSToolkitポッドをインポートすることと相まって、うまく機能します。これが最も簡単な方法だと思います。
Chris

クリス、ありがとう!お役に立てて嬉しいです。
Sam Soffes 2013年

14

迅速

 class TextField: UITextField {

    let inset: CGFloat = 8

    // placeholder position
    override func textRect(forBounds bounds: CGRect) -> CGRect {
        return bounds.insetBy(dx: inset, dy: inset)
    }

    // text position
    override func editingRect(forBounds bounds: CGRect) -> CGRect {
        return bounds.insetBy(dx: inset, dy: inset)
    }
}

奇妙なことに、テキストが表示可能な四角形をオーバーフローするとき、これは(少なくともiOS 12では)スクロールパフォーマンスに影響します。15のインセットでは、スクロールも停止します。
Ixx

12

より簡単な解決策を探している人のために。

UITextField内部を追加しUIViewます。テキストフィールドの周囲のインセットをシミュレートするために、左に10ピクセル、幅をビューより20ピクセル小さくします。テキストフィールドの周りの角が丸いボーダーの場合は、ビューのボーダーを使用します

viewBG.layer.cornerRadius = 8.0;
viewBG.layer.borderColor = [UIColor darkGrayColor].CGColor;
viewBG.layer.borderWidth = 1.0;

2
正直なところ、UIViewをUITextFieldの背後に配置するだけが、最善かつ最も簡単なソリューションです。UITextFieldを透明にして行います。私はそれをUITextViewに合わせました-約6ピクセルのはめ込みになります。サブクラスを作成するよりもはるかに簡単で柔軟性もあります...
n13

この方法の問題は、スクロールバーが表示される場所です。
Doug Amos

@DougAmosどんなスクロールバー?あなたはUITextViewおそらく言及していますか?
意味の問題

12

leftViewを設定することで、UITextFieldのテキストインセットを設定できます。

このような:

UITextField *yourTextField = [[UITextField alloc] init];
UIView *leftView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 5, 5)];
leftView.backgroundColor = [UIColor clearColor];
yourTextField.leftViewMode = UITextFieldViewModeAlways;
yourTextField.leftView = leftView;

1
アイコンにレフトビューも使用する必要がある場合、これは機能しません
Reaper

@Reaperこのメソッドは画像に対しても機能します。imageviewフレームの幅に必要なパディングの量を追加し、contentmodeを中央に設定します。imageView.contentMode = UIViewContentMode.Center imageView.frame = CGRectMake(0.0, 0.0, imageView.image!.size.width + 16.0, imageView.image!.size.height)
アンディ

これはあまりにもハックです。インセットを設定するためのtextRectForBoundsメソッドがすでに存在します
Gerald

12

迅速

    // adjust place holder text
    let paddingView = UIView(frame: CGRectMake(0, 0, 10, usernameOrEmailField.frame.height))
    usernameOrEmailField.leftView = paddingView
    usernameOrEmailField.leftViewMode = UITextFieldViewMode.Always

1
これは本当に安くて簡単な回避策です。ありがとう!
shnaz

11

UITextFieldにパディングを追加する良い方法は、UITextFieldをサブクラス化して、edgeInsetsプロパティを追加することです。次に、edgeInsetsを設定すると、それに応じてUITextFieldが描画されます。これは、カスタムのleftViewまたはrightViewセットでも正しく機能します。

OSTextField.h

#import <UIKit/UIKit.h>

@interface OSTextField : UITextField

@property (nonatomic, assign) UIEdgeInsets edgeInsets;

@end

OSTextField.m

#import "OSTextField.h"

@implementation OSTextField

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

-(id)initWithCoder:(NSCoder *)aDecoder{
    self = [super initWithCoder:aDecoder];
    if(self){
        self.edgeInsets = UIEdgeInsetsMake(0, 0, 0, 0);
    }
    return self;
}

- (CGRect)textRectForBounds:(CGRect)bounds {
    return [super textRectForBounds:UIEdgeInsetsInsetRect(bounds, self.edgeInsets)];
}

- (CGRect)editingRectForBounds:(CGRect)bounds {
    return [super editingRectForBounds:UIEdgeInsetsInsetRect(bounds, self.edgeInsets)];
}

@end

いい答えです。不足しているプロパティを提供します:-)
ファットマン

6

Swift 3 / Interface Builderで設計可能/水平と垂直の独立した昆虫/箱から出して使用可能

@IBDesignable
class TextFieldWithPadding: UITextField {

@IBInspectable var horizontalInset: CGFloat = 0
@IBInspectable var verticalInset: CGFloat = 0

override func textRect(forBounds bounds: CGRect) -> CGRect {
    return bounds.insetBy(dx: horizontalInset, dy: verticalInset)
}

override func editingRect(forBounds bounds: CGRect) -> CGRect {
    return bounds.insetBy(dx: horizontalInset , dy: verticalInset)
}

override func placeholderRect(forBounds bounds: CGRect) -> CGRect {
    return bounds.insetBy(dx: horizontalInset, dy: verticalInset)
}
}

使用法:

使用法

ここに画像の説明を入力してください



5

これは、サブクラスを作成せずに見つけた最も速い方法です。

UIView *spacerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10., 10.)];
[textField setLeftViewMode:UITextFieldViewModeAlways];
[textField setLeftView:spacerView];

Swiftの場合:

let spacerView = UIView(frame:CGRect(x:0, y:0, width:10, height:10))
textField.leftViewMode = UITextFieldViewMode.Always
textField.leftView = spacerView

4

以下は、Swift 3で作成された同じサブクラス化されたUITextFieldです。これは、以前のバージョンのSwiftとはかなり異なります。

import UIKit

class MyTextField: UITextField
    {
    let inset: CGFloat = 10

    // placeholder position
    override func textRect(forBounds bounds: CGRect) -> CGRect
        {
        return bounds.insetBy(dx: inset, dy: inset)
        }

    // text position
    override func editingRect(forBounds bounds: CGRect) -> CGRect
        {
        return bounds.insetBy(dx: inset, dy: inset)
        }

    override func placeholderRect(forBounds bounds: CGRect) -> CGRect
        {
        return bounds.insetBy(dx: inset, dy: inset)
        }
    }

ちなみに、片側だけのインセットを制御したい場合は、次のようなこともできます。左インセットのみを調整するこの特定の例は、UITextFieldの上に画像を配置し、ユーザーにはテキストフィールド内に表示したい場合に便利です。

    override func editingRect(forBounds bounds: CGRect) -> CGRect
        {
        return CGRect.init(x: bounds.origin.x + inset, y: bounds.origin.y, width: bounds.width - inset, height: bounds.height)
        }

4

Swift 4.2バージョン:

import UIKit

class InsetTextField: UITextField {

  let inset: CGFloat = 10

  override func textRect(forBounds bounds: CGRect) -> CGRect {
    return bounds.insetBy(dx: inset, dy: inset)
  }


  override func editingRect(forBounds bounds: CGRect) -> CGRect {
    return bounds.insetBy(dx: inset, dy: inset)
  }

  override func placeholderRect(forBounds bounds: CGRect) -> CGRect {
    return bounds.insetBy(dx: inset, dy: inset)
  }

}

奇妙なことに、テキストが表示可能な四角形をオーバーフローするとき、これは(少なくともiOS 12では)スクロールパフォーマンスに影響します。15のインセットでは、スクロールも停止します。
Ixx

3

メソッドのサブクラスにUITextFieldして-textRectForBounds:メソッドをオーバーライドすることにより、テキストフィールド内のテキストの位置を調整できます。


3

UITextField@Adam Waiteが指摘しているように、すでにメソッドを実装しているので、サブクラス化する必要があるのはばかげています。以下は、ファクトリメソッドを公開する迅速な拡張です。これは、カテゴリrepoでも使用できます。

private class InsetTextField: UITextField {
    var insets: UIEdgeInsets

    init(insets: UIEdgeInsets) {
        self.insets = insets
        super.init(frame: CGRectZero)
    }

    required init(coder aDecoder: NSCoder) {
        fatalError("not intended for use from a NIB")
    }

    // placeholder position
    override func textRectForBounds(bounds: CGRect) -> CGRect {
        return super.textRectForBounds(UIEdgeInsetsInsetRect(bounds, insets))
    }

    // text position
    override func editingRectForBounds(bounds: CGRect) -> CGRect {
        return super.editingRectForBounds(UIEdgeInsetsInsetRect(bounds, insets))
    }
}

extension UITextField {

    class func textFieldWithInsets(insets: UIEdgeInsets) -> UITextField {
        return InsetTextField(insets: insets)
    }

}

回答のリンクが無効になっています。更新できますか?
WendiKidd 2015

URLを修正しました@WendiKidd
Christopher Pickslay

2

これを処理するUITextFieldをサブクラス化して、左、上、右、下のインセットをサポートし、ボタンの配置もクリアしました。

MRDInsetTextField.h

#import <UIKit/UIKit.h>

@interface MRDInsetTextField : UITextField

@property (nonatomic, assign) CGRect inset;

@end

MRDInsetTextField.m

#import "MRDInsetTextField.h"

@implementation MRDInsetTextField

- (id)init
{
    self = [super init];
    if (self) {
        _inset = CGRectZero;
    }
    return self;
}

- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (self) {
        _inset = CGRectZero;
    }
    return self;
}

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        _inset = CGRectZero;
    }
    return self;
}

- (void)setInset:(CGRect)inset {
    _inset = inset;

    [self setNeedsLayout];
}

- (CGRect)getRectForBounds:(CGRect)bounds withInset:(CGRect)inset {

    CGRect newRect = CGRectMake(
                         bounds.origin.x + inset.origin.x,
                         bounds.origin.y + inset.origin.y,
                         bounds.origin.x + bounds.size.width - inset.origin.x - inset.size.width,
                         bounds.origin.y + bounds.size.height - inset.origin.y - inset.size.height
                         );

    return newRect;
}

- (CGRect)textRectForBounds:(CGRect)bounds {
    return [self getRectForBounds:[super textRectForBounds:bounds] withInset:_inset];
}

- (CGRect)placeholderRectForBounds:(CGRect)bounds {
    return [self getRectForBounds:bounds withInset:_inset];
}

- (CGRect)editingRectForBounds:(CGRect)bounds {
    return [self getRectForBounds:[super editingRectForBounds:bounds] withInset:_inset];
}

- (CGRect)clearButtonRectForBounds:(CGRect)bounds {
    return CGRectOffset([super clearButtonRectForBounds:bounds], -_inset.size.width, _inset.origin.y/2 - _inset.size.height/2);
}

@end

* _someTextField *がMRDInsetTextFieldカスタムクラスのnib / storyboardビューから取得される使用例

[(MRDInsetTextField*)_someTextField setInset:CGRectMake(5, 0, 5, 0)]; // left, top, right, bottom inset

ありがとうございました。しかし、コードに対する1つの提案-なぜUIEdgeInsetsではなく、インセットにCGRectを使用したのですか?
sha 14

2

これは他の例ほど短くはありませんが、この問題を解決するためにまったく異なるアプローチを取ります。キャレットは依然として左端にフラッシュし始めますが、入力/表示すると、テキストは適切にインデントされます。これは、左マージンだけを探していてUITextFieldDelegate、テキストフィールドにすでに使用している場合、サブクラス化なしで機能します。デフォルトのテキスト属性と入力属性の両方を設定する必要があります。テキストフィールドを作成するときに、デフォルトのテキスト属性を設定します。デリゲートで設定する必要がある入力属性。プレースホルダーも使用している場合は、それも同じマージンに設定する必要があります。まとめると、このようなものになります。

まず、UITextFieldクラスにカテゴリを作成します。

//  UITextField+TextAttributes.h

#import <UIKit/UIKit.h>

@interface UITextField (TextAttributes)

- (void)setIndent:(CGFloat)indent;

@end


//  UITextField+TextAttributes.m
#import "UITextField+TextAttributes.h"

@implementation UITextField (TextAttributes)

- (void)setTextAttributes:(NSDictionary*)textAttributes indent:(CGFloat)indent
{
    if (!textAttributes) return;

    NSMutableParagraphStyle *paragraphStyle = [textAttributes objectForKey:NSParagraphStyleAttributeName];
    paragraphStyle.firstLineHeadIndent = indent;
    paragraphStyle.headIndent = indent;
}

- (void)setIndent:(CGFloat)indent
{
   [self setTextAttributes:self.defaultTextAttributes indent:indent];
   [self setTextAttributes:self.typingAttributes indent:indent];
}

@end

次に、プレースホルダーを使用している場合は、同じインデントを設定した属性付きプレースホルダーを使用してください。次のような適切な属性を持つデフォルトの属性付き辞書を作成します。

NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.firstLineHeadIndent = 7;
paragraphStyle.headIndent = 7;
NSDictionary *placeholderAttributes = [NSDictionary dictionaryWithObjectsAndKeys: paragraphStyle, NSParagraphStyleAttributeName, nil];

次に、上記のカテゴリをインポートし、テキストフィールドを作成するたびにデフォルトのインデント、デリゲートを設定し、上記で定義したデフォルトのプレースホルダー属性を使用します。例えば:

UITextField *textField = [[UITextField alloc] init];
textField.indent = 7;
textField.delegate = self;
textField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:@"Placeholder Text" attributes:placeholderAttributes];

最後に、デリゲートでtextFieldDidBeginEditing、次のようなメソッドを実装します。

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
    textField.indent = 7;
}

defaultTextAttributes含むという仮定NSMutableParagraphStyleは非常に危険です。私はむしろこれらすべてをmutableCopyにしたいと思います。
Ben Sinclair

1

私は通常サブクラス化を避けようとしますが、これはすでに持っている場合は機能します:

// add a property 
@property (nonatomic) UIEdgeInsets edgeInsets;

// and override:

- (CGRect)textRectForBounds:(CGRect)bounds
{
    return [super textRectForBounds:UIEdgeInsetsInsetRect(bounds, self.edgeInsets)];
}

- (CGRect)editingRectForBounds:(CGRect)bounds
{
    return [super editingRectForBounds:UIEdgeInsetsInsetRect(bounds, self.edgeInsets)];
}

サブクラス化を避ける理由は何ですか?これ有効な設計パラダイムです。
Stunner、2015年

1

サブクラス化の必要がない別のソリューションを投入するには:

UITextField *txtField = [UITextField new];
txtField.borderStyle = UITextBorderStyleRoundedRect;

// grab BG layer
CALayer *bgLayer = txtField.layer.sublayers.lastObject;
bgLayer.opacity = 0.f;

// add new bg view
UIView *bgView = [UIView new];
bgView.backgroundColor = [UIColor whiteColor];
bgView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
bgView.userInteractionEnabled = NO;

[txtField addSubview: bgView];
[txtField sendSubviewToBack: bgView];

元のUITextField 修正されたUITextField

iOS 7とiOS 8でテスト済み。どちらも機能しています。それでも、AppleがUITextFieldのレイヤー階層を変更して、物事をひどく混乱させる可能性があります。


1

以下は、左ビュー(カスタムアイコン)とカスタムクリアボタンを含む包括的なSwift回答です。どちらもInterface Builderでカスタマイズ可能なインセットを使用して設定されています。

import UIKit

@IBDesignable
class InsetTextField: UITextField {
@IBInspectable var leftInset:CGFloat = 0
@IBInspectable var rightInset:CGFloat = 0
@IBInspectable var icon:UIImage? { didSet {
    let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 16, height: 16))
    imageView.image = icon
    self.leftView = imageView
    self.leftViewMode = .Always
} }

@IBInspectable var clearButton:UIImage? { didSet {
    let button = UIButton(type: .Custom)
    button.setImage(clearButton, forState: .Normal)
    button.addTarget(self, action: "clear", forControlEvents: UIControlEvents.TouchUpInside)
    button.frame = CGRect(x: 0, y: 0, width: 18, height: 18)
    self.rightView = button
    self.rightViewMode = .WhileEditing
} }

func clear() {
    self.text = ""
}

override func leftViewRectForBounds(bounds: CGRect) -> CGRect {
    var height:CGFloat = 0
    var width:CGFloat = 0
    if let leftView = self.leftView {
        height = leftView.bounds.height
        width = leftView.bounds.width
    }

    return CGRect(x: leftInset, y: bounds.height/2 - height/2, width: width, height: height)
}

override func rightViewRectForBounds(bounds: CGRect) -> CGRect {
    var height:CGFloat = 0
    var width:CGFloat = 0
    if let rightView = self.rightView {
        height = rightView.bounds.height
        width = rightView.bounds.width
    }

    return CGRect(x: bounds.width - width - rightInset, y: bounds.height/2 - height/2, width: width, height: height)
}

}

1

実際に機能し、すべてのケースをカバーするソリューション:

  • 使用しoffsetByないでくださいinsetBy
  • オリジナルを取得するには、super関数も呼び出す必要がありますRect
  • 境界に欠陥があります。元のX、Yをオフセットする必要があります。境界はX、Yをゼロとします。
  • たとえば、UITextFieldのleftViewを設定する場合、元のx、yはゼロ以外にすることができます。

サンプル:

override func textRect(forBounds bounds: CGRect) -> CGRect {
    return super.textRect(forBounds: bounds).offsetBy(dx: 0.0, dy: 4)
}


override func editingRect(forBounds bounds: CGRect) -> CGRect {
    return super.editingRect(forBounds: bounds).offsetBy(dx: 0.0, dy: 4)
}

0

TOPとLEFTのインデントのみを変更したい場合

//プレースホルダーの位置

- (CGRect)textRectForBounds:(CGRect)bounds {

CGRect frame = bounds;
frame.origin.y = 3;
 frame.origin.x = 5;
bounds = frame;
return CGRectInset( bounds , 0 , 0 );
}

//テキストの位置

- (CGRect)editingRectForBounds:(CGRect)bounds {

CGRect frame = bounds;
frame.origin.y = 3;
 frame.origin.x = 5;
bounds = frame;
return CGRectInset( bounds , 0 , 0 );
}

-1

サブクラスがなく、検査可能なクイックソリューション

extension UITextField {
    @IBInspectable var textInsets: CGPoint {
            get {
                return CGPoint.zero
            }
            set {
                layer.sublayerTransform = CATransform3DMakeTranslation(newValue.x, newValue.y, 0);
            }
        }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.