Jawaban:
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);
}
UITextField
berada di dalam a UIScrollView
.
- (CGRect)clearButtonRectForBounds:(CGRect)bounds { return CGRectMake(x, y, w, h); }
Ditemukan di sini: stackoverflow.com/questions/5361369/...
Saya bisa melakukannya melalui:
myTextField.layer.sublayerTransform = CATransform3DMakeTranslation(5, 0, 0);
Tentu saja ingatlah untuk mengimpor QuartzCore dan juga menambahkan Framework ke proyek Anda.
UITextField
tumpang tindih konten di sebelah kanannya.
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.
leftView.backgroundColor = textField.backgroundColor;
... Selain itu solusi hebat ... Terima kasih (:
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.
- (CGRect)borderRectForBounds:(CGRect)bounds; - (CGRect)placeholderRectForBounds:(CGRect)bounds; - (CGRect)clearButtonRectForBounds:(CGRect)bounds; - (CGRect)leftViewRectForBounds:(CGRect)bounds; - (CGRect)rightViewRectForBounds:(CGRect)bounds;
Bagaimana dengan @IBInspectable
, @IBDesignable
kelas 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.
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)
}
}
let rect = CGRect(x: bounds.minX, y: bounds.minY + insetY, width: bounds.width, height: bounds.height) return CGRectInset(rect , insetX , 0)
textRect
/ editingRect
) memengaruhi kinerja pengguliran (setidaknya di iOS 12), ketika teks meluap kotak yang terlihat. Dengan inset 15 bahkan berhenti bergulir.
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 super
pertama, 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 .
textRectForBounds:
dan editingRectForBounds:
metode tanpa clearButtonRectForBounds:
di iOS 7+ bekerja untuk saya.
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.
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)
}
}
override func placeholderRectForBounds(bounds: CGRect) -> CGRect { return CGRectInset(bounds, inset, inset) }
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.
Menggunakan textRectForBounds:
adalah pendekatan yang benar. Saya telah membungkus ini dalam subkelas saya sehingga Anda bisa menggunakannya textEdgeInsets
. Lihat SSTextField .
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)
}
}
Untuk orang-orang, yang mencari solusi yang lebih mudah.
Tambahkan bagian UITextField
dalam 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;
UITextView
mungkin?
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;
imageView.contentMode = UIViewContentMode.Center imageView.frame = CGRectMake(0.0, 0.0, imageView.image!.size.width + 16.0, imageView.image!.size.height)
Cepat
// adjust place holder text
let paddingView = UIView(frame: CGRectMake(0, 0, 10, usernameOrEmailField.frame.height))
usernameOrEmailField.leftView = paddingView
usernameOrEmailField.leftViewMode = UITextFieldViewMode.Always
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
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:
&
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
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)
}
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)
}
}
Anda dapat menyesuaikan posisi teks dalam bidang teks dengan menjadikannya subclass UITextField
dan menimpa -textRectForBounds:
metode.
Tidak masuk akal Anda harus subclass, karena UITextField
sudah 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)
}
}
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
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 UITextField
kelas.
// 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 textFieldDidBeginEditing
metode, seperti ini:
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
textField.indent = 7;
}
defaultTextAttributes
berisi NSMutableParagraphStyle
cukup berbahaya .. Saya lebih suka mutableCopy semua ini.
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)];
}
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];
Diuji dengan iOS 7 dan iOS 8. Keduanya berfungsi. Masih ada kemungkinan Apple memodifikasi hierarki lapisan UITextField yang mengacaukan segalanya.
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)
}
}
Solusi yang benar-benar berfungsi dan mencakup semua kasus:
offsetBy
tidak digunakan insetBy
.Rect
.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)
}
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 );
}
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);
}
}
}