Inset teks untuk UITextField?


Jawaban:


628

Mengesampingkan -textRectForBounds:hanya akan mengubah inset teks placeholder. Untuk mengubah inset teks yang dapat diedit, Anda juga harus mengganti-editingRectForBounds:

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

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

10
Solusi ini bekerja untuk saya, meskipun saya menggunakan nilai pengembalian CGRectInset (batas, 9, 0); Saya juga perlu menetapkan nilai ini untuk textRectForBounds, mengeditRectForBounds, dan placeholderRectForBounds.
RyJ

2
Solusi ini tidak cocok dengan clearButton. Teks di dalam tombol overlay TextField.
Piotr

Saya pikir, mengganti metode di atas akan menyebabkan gulir lambat, jika UITextFieldberada di dalam a UIScrollView.
Bharat Dodeja

2
Untuk menempatkan ClearButton: - (CGRect)clearButtonRectForBounds:(CGRect)bounds { return CGRectMake(x, y, w, h); } Ditemukan di sini: stackoverflow.com/questions/5361369/...
Miros

22
Saya sarankan untuk memanggil [super textRectForBounds: bounds] dan [super editingRectForBounds: bounds] sebelum memanggil CGRectInset (bounds, 10, 10). Ini akan memperbaiki masalah overlay tombol hapus.
mrvincenzo

294

Saya bisa melakukannya melalui:

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

Tentu saja ingatlah untuk mengimpor QuartzCore dan juga menambahkan Framework ke proyek Anda.


38
+1 untuk kreativitas, tetapi ini sedikit bermasalah, ia bergerak juga menghapus tombol di dalam bidang teks
Nikita

2
Anda dapat melakukan myTextField.layer.sublayers yang merupakan array dari semua sublayers ... dan jika UIImageView <- Saya berasumsi X adalah gambar .. atau mungkin UIButton ... atau Anda dapat mengulangi masing-masing dan melihat yang mana milik subview mana ... tapi myfield.layer.sublayerTransformasi semua sublayer dan dengan demikian tombol X bergerak juga ..
chuthan20

Solusi ini tidak berfungsi untuk saya. Saya hanya dapat mengatur margin Kiri dan Atas tetapi tidak kanan dan bawah. UITextFieldtumpang tindih konten di sebelah kanannya.
Bharat Dodeja

2
Ini adalah solusi terbaik tanpa subclassing dan tidak memerlukan tampilan tambahan yang tidak perlu ditempatkan di layar! +1!
Rambatino

1
@ jeet.chanchawat Tombol X di sisi kanan dalam gambar ini .. developer.apple.com/library/content/documentation/…
chuthan20

169

Jika Anda hanya membutuhkan margin kiri, Anda dapat mencoba ini:

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;

Ini bekerja untuk saya. Saya harap ini bisa membantu.


17
Ini jauh lebih mudah daripada subklas hanya untuk mendapatkan inset, dan memungkinkan Anda menambahkan tampilan sembarang di sebelah kiri (Anda juga dapat menggunakan rightView untuk meletakkan sesuatu di sebelah kanan). Lebih baik dari jawaban IMHO yang diterima.
Kenny Grant

4
+1 mudah, tanpa subklasifikasi, dan dirancang untuk bekerja dengan properti textfield (bukan 'peretasan').
So Over It

Baris ketiga harus leftView.backgroundColor = textField.backgroundColor;... Selain itu solusi hebat ... Terima kasih (:
Aviel Gross

Tidak cukup elegan / menyeluruh seperti jawaban azdev, tetapi solusi yang bagus untuk kasus umum dan sederhana!
Rembrandt Q. Einstein

1
Subklasifikasi akan menghemat banyak waktu untuk jawaban ini, kecuali jika Anda memiliki satu kotak teks saja.
Crake

168

Di kelas yang berasal dari UITextField, timpa setidaknya dua metode ini:

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

Mungkin sesederhana ini jika Anda tidak memiliki konten tambahan:

return CGRectInset(bounds , 10, 10);

UITextField menyediakan beberapa metode penentuan posisi yang dapat Anda abaikan.


2
ya, jika Anda tidak mengganti editingRectForBounds Anda mendapatkan teks saat mengedit di kiri atas bidang teks. - (CGRect) editingRectForBounds: (CGRect) bounds {return CGRectInset (bounds, 10, 10); }
Mark W

1
Baru diedit jawaban untuk mengintegrasikan metode editingRectForBounds ke
ıɾuǝʞ

5
- (CGRect)borderRectForBounds:(CGRect)bounds; - (CGRect)placeholderRectForBounds:(CGRect)bounds; - (CGRect)clearButtonRectForBounds:(CGRect)bounds; - (CGRect)leftViewRectForBounds:(CGRect)bounds; - (CGRect)rightViewRectForBounds:(CGRect)bounds;
Bagi

98

Bagaimana dengan @IBInspectable, @IBDesignablekelas cepat.

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

Anda akan melihat ini di storyboard Anda.

masukkan deskripsi gambar di sini

Perbarui - 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
Saya menemukan efek pada Y yang tidak diinginkan, saya tidak ingin mengecilkan rect untuk teks, agak mendorongnya ke bawah ke garis dasar lapangan. Saya menyesuaikan implementasinya kelet rect = CGRect(x: bounds.minX, y: bounds.minY + insetY, width: bounds.width, height: bounds.height) return CGRectInset(rect , insetX , 0)
Chris Wagner

1
Dan tambahkan ini juga jika Anda menggunakan placeholder `override func placeholderRectForBounds (batas: CGRect) -> CGRect {return CGRectInset (batas, insX, insetY)}`
RameshVel

Anehnya ini (pengaturan insets di textRect/ editingRect) memengaruhi kinerja pengguliran (setidaknya di iOS 12), ketika teks meluap kotak yang terlihat. Dengan inset 15 bahkan berhenti bergulir.
Ixx

29

Jika Anda memiliki tombol yang jelas, jawaban yang diterima tidak akan bekerja untuk Anda. Kita juga harus menjaga agar Apple tidak mengubah hal-hal di masa depan dengan menelepon super.

Jadi, untuk memastikan teks tidak tumpang tindih tombol yang jelas, mari kita dapatkan nilai 'default' dari superpertama, lalu sesuaikan seperlunya.

Kode ini akan menambahkan insets 10px di bagian atas, kiri dan bawah bidang teks:

@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

Catatan: UIEdgeInsetsMake mengambil parameter dalam urutan: atas , kiri , bawah , kanan .


Menggunakan textRectForBounds:dan editingRectForBounds:metode tanpa clearButtonRectForBounds: di iOS 7+ bekerja untuk saya.
Stunner

clearButtonRectForBounds:hanya membantu mendorong sedikit tombol ke kiri sedikit. Anda mungkin ingin meninggalkannya. Bidang teks saya berada di latar belakang gelap, dan tombol yang jelas membutuhkan sedikit tambahan di sebelah kanan.
Chris Nolet

Anehnya ini mempengaruhi kinerja pengguliran (setidaknya di iOS 12), ketika teks meluap persegi terlihat. Dengan inset 15 bahkan berhenti bergulir.
Ixx

22

Pikir saya akan menyediakan Solusi 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
Jangan lupa override func placeholderRectForBounds(bounds: CGRect) -> CGRect { return CGRectInset(bounds, inset, inset) }
Eugene Braginets

Dalam Swift 3 Anda harus menggunakan metode 'CGRect.insetBy ()'
Den

1
Di iOS 11 setidaknya, jika Anda menimpa textRectForBounds, placeholder juga terpengaruh - jadi menambahkan placeholder menimpa insets placeholder lain 10pt lebih jauh. Jika itu yang Anda cari, 👍🏼, tetapi jika tidak, ada baiknya Anda waspadai.
Ditunjuknerd

Anehnya ini mempengaruhi kinerja pengguliran (setidaknya di iOS 12), ketika teks meluap persegi terlihat. Dengan inset 15 bahkan berhenti bergulir.
Ixx

14

Menggunakan textRectForBounds:adalah pendekatan yang benar. Saya telah membungkus ini dalam subkelas saya sehingga Anda bisa menggunakannya textEdgeInsets. Lihat SSTextField .


Pendekatan ini, bersama dengan menggunakan cocoapods untuk mengimpor pod SSToolkit, sangat bagus - saya pikir ini adalah cara yang paling rapi untuk digunakan.
Chris

Terimakasih Chris! Senang Anda menemukannya bermanfaat.
Sam Soffes

14

Cepat

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

Anehnya ini mempengaruhi kinerja pengguliran (setidaknya di iOS 12), ketika teks meluap persegi terlihat. Dengan inset 15 bahkan berhenti bergulir.
Ixx

12

Untuk orang-orang, yang mencari solusi yang lebih mudah.

Tambahkan bagian UITextFielddalam a UIView. Untuk mensimulasikan inset di sekitar bidang teks saya tetap 10 px kiri dan lebarnya 20px kurang dari tampilan. Untuk perbatasan sudut bulat di sekitar bidang teks, gunakan perbatasan tampilan

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

2
Jujur saja menempatkan UIView di belakang UITextField adalah solusi terbaik dan paling sederhana. Jadikan UITextField transparan dan selesai. Saya menyelaraskannya dengan UITextView - ternyata inset sekitar 6 piksel. Jauh lebih mudah dan juga lebih fleksibel daripada membuat subclass ...
n13

Masalah dengan pendekatan ini adalah lokasi di mana bilah gulir akan muncul.
Doug Amos

@DougAmos Apa scrollbar? Apakah Anda merujuk UITextViewmungkin?
maknanya penting

12

Anda dapat mengatur inset teks untuk UITextField dengan mengatur leftView.

Seperti ini:

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
Ketika Anda juga perlu menggunakan tampilan kiri untuk ikon, ini tidak bisa bekerja
Reaper

@Reaper metode ini juga akan berfungsi untuk gambar. tambahkan jumlah padding yang Anda inginkan ke lebar bingkai tampilan gambar dan atur contentmode ke tengah. imageView.contentMode = UIViewContentMode.Center imageView.frame = CGRectMake(0.0, 0.0, imageView.image!.size.width + 16.0, imageView.image!.size.height)
Andy

ini terlalu hacky. sudah ada metode textRectForBounds untuk menyetel inset
Gerald

12

Cepat

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

1
Ini adalah solusi yang sangat murah dan mudah. Terima kasih!
shnaz

11

Pendekatan yang baik untuk menambahkan padding ke UITextField adalah dengan subclass UITextField dan menambahkan properti edgeInsets. Anda kemudian mengatur edgeInsets dan UITextField akan ditarik sesuai. Ini juga akan berfungsi dengan benar dengan set custom leftView atau 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

Jawaban yang bagus. Persediaan properti yang hilang :-)
phatmann

6

Swift 3 / Designable in Interface builder / Pisahkan serangga horizontal & vertikal / dapat digunakan di luar kotak

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

pemakaian:

pemakaian

&

masukkan deskripsi gambar di sini


5

Saya melakukan ini di IB di mana saya membuat UIView Di belakang textView yang sedikit lebih lama. Dengan warna latar belakang textField diatur ke jelas. masukkan deskripsi gambar di sini


5

Ini adalah cara tercepat yang saya temukan tanpa melakukan subclass:

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

Dalam Swift:

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

4

Berikut adalah subclass yang sama dengan UITextField yang ditulis dalam Swift 3. Ini sangat berbeda dari versi Swift sebelumnya, seperti yang akan Anda lihat:

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

Kebetulan, Anda juga dapat melakukan sesuatu seperti berikut ini, jika Anda ingin mengontrol inset hanya dari satu sisi. Contoh khusus ini hanya menyesuaikan inset kiri berguna jika Anda menempatkan gambar di atas UITextField tetapi Anda ingin itu muncul kepada pengguna berada di dalam bidang teks:

    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

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

}

Anehnya ini mempengaruhi kinerja pengguliran (setidaknya di iOS 12), ketika teks meluap persegi terlihat. Dengan inset 15 bahkan berhenti bergulir.
Ixx

3

Anda dapat menyesuaikan posisi teks dalam bidang teks dengan menjadikannya subclass UITextFielddan menimpa -textRectForBounds:metode.


3

Tidak masuk akal Anda harus subclass, karena UITextFieldsudah mengimplementasikan metode, seperti yang ditunjukkan oleh @Adam Waite. Berikut ekstensi cepat yang memperlihatkan metode pabrik, juga tersedia di repo kategori kami :

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

}

Tautan dalam jawaban Anda sudah mati, dapatkah Anda memperbaruinya?
WendiKidd

Memperbaiki URL @WendiKidd
Christopher Pickslay

2

Saya subclased UITextField untuk menangani ini yang mendukung inset kiri, atas, kanan dan bawah, dan juga pemosisian tombol yang jelas.

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

Contoh penggunaan di mana * _someTextField * berasal dari tampilan nib / storyboard dengan kelas khusus MRDInsetTextField

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

Terima kasih. Satu saran untuk kode Anda - mengapa Anda menggunakan CGRect untuk inset dan bukan UIEdgeInsets?
sha

2

Ini tidak sesingkat contoh lainnya, tetapi mengambil pendekatan yang sama sekali berbeda untuk menyelesaikan masalah ini. Catatan, tanda sisir masih akan mulai rata ke tepi kiri tetapi teks akan indentasi dengan benar ketika diketik / ditampilkan. Ini berfungsi tanpa subklasifikasi jika Anda mencari margin kiri dan Anda sudah menggunakanUITextFieldDelegate untuk bidang teks Anda. Anda perlu mengatur atribut teks standar dan atribut pengetikan. Anda menetapkan atribut teks default saat Anda membuat bidang teks. Atribut pengetikan yang perlu Anda atur dalam delegasi. Jika Anda juga menggunakan placeholder, Anda akan ingin mengaturnya ke margin yang sama juga. Secara keseluruhan, Anda mendapatkan sesuatu seperti ini.

Pertama buat kategori di UITextFieldkelas.

//  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

Kemudian, jika Anda menggunakan pemegang yang ditempatkan pastikan untuk menggunakan placeholder yang dikaitkan dengan pengaturan indentasi yang sama. Buat kamus bawaan yang dikaitkan dengan atribut yang tepat, seperti ini:

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

Kemudian, impor kategori di atas dan setiap kali Anda membuat bidang teks setel indentasi default, delegasikan dan gunakan atribut placeholder default yang ditentukan di atas. Sebagai contoh:

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

Terakhir, dalam delegasi, implementasikan textFieldDidBeginEditingmetode, seperti ini:

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

Asumsi yang defaultTextAttributesberisi NSMutableParagraphStylecukup berbahaya .. Saya lebih suka mutableCopy semua ini.
Ben Sinclair

1

Saya biasanya mencoba menghindari subclassing tetapi ini berfungsi jika Anda sudah:

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

Ada alasan mengapa Anda menghindari subclassing? Ini adalah paradigma desain yang valid.
Stunner

1

Untuk melempar solusi lain yang tidak perlu subklas:

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 Asli Memperbaiki UITextField

Diuji dengan iOS 7 dan iOS 8. Keduanya berfungsi. Masih ada kemungkinan Apple memodifikasi hierarki lapisan UITextField yang mengacaukan segalanya.


1

Inilah jawaban Swift komprehensif yang mencakup leftView (ikon kustom) dan tombol hapus kustom, keduanya diatur dalam Interface Builder dengan insets yang dapat disesuaikan.

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

Solusi yang benar-benar berfungsi dan mencakup semua kasus:

  • Seharusnya offsetBytidak digunakan insetBy.
  • Harus juga memanggil fungsi super untuk mendapatkan yang asli Rect.
  • Batas rusak. Anda perlu mengimbangi X asli, Y. Batas memiliki X, Y sebagai nol.
  • Original x, y dapat berupa non-nol misalnya ketika mengatur leftView dari UITextField.

Sampel:

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

Jika Anda hanya ingin mengubah indentasi TOP dan LEFT saja

// posisi placeholder

- (CGRect)textRectForBounds:(CGRect)bounds {

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

// posisi teks

- (CGRect)editingRectForBounds:(CGRect)bounds {

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

-1

Solusi cepat tanpa subkelas & juga dapat diperiksa

extension UITextField {
    @IBInspectable var textInsets: CGPoint {
            get {
                return CGPoint.zero
            }
            set {
                layer.sublayerTransform = CATransform3DMakeTranslation(newValue.x, newValue.y, 0);
            }
        }
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.