UITextField
をロードするときに、iPhone SDK での最大文字数を設定するにはどうすればよいUIView
ですか?
UITextField
をロードするときに、iPhone SDK での最大文字数を設定するにはどうすればよいUIView
ですか?
回答:
一方でUITextField
クラスが何の最大長プロパティを持っていない、それはテキストフィールドのを設定することによって、この機能を取得するには、比較的簡単ですdelegate
し、次のデリゲートメソッドを実装します:
Objective-C
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
// Prevent crashing undo bug – see note below.
if(range.length + range.location > textField.text.length)
{
return NO;
}
NSUInteger newLength = [textField.text length] + [string length] - range.length;
return newLength <= 25;
}
迅速
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let currentCharacterCount = textField.text?.count ?? 0
if range.length + range.location > currentCharacterCount {
return false
}
let newLength = currentCharacterCount + string.count - range.length
return newLength <= 25
}
テキストフィールドが変更される前に、UITextFieldはデリゲートに指定されたテキストを変更する必要があるかどうかを尋ねます。この時点ではテキストフィールドは変更されていないため、現在の長さと(コピーしたテキストを貼り付けるか、キーボードを使用して1文字を入力して)挿入する文字列の長さから、範囲の長さを引いたものを取得します。この値が長すぎる(この例では25文字を超える)場合は、戻っNO
て変更を禁止します。
テキストフィールドの末尾に単一の文字を入力range.location
すると、現在のフィールドの長さがになり、range.length
何も置換/削除しないため、0になります。テキストフィールドの中央に挿入するということは、単にが異なることを意味し、range.location
複数の文字を貼り付けることは、その中に複数の文字があることを意味string
します。
単一の文字の削除または複数の文字のカットはrange
、長さがゼロ以外のa と空の文字列で指定されます。置換は、空ではない文字列を含む範囲の削除です。
コメントに記載されているように、UITextField
クラッシュの原因となるバグがあります。
フィールドに貼り付けたが、検証の実装によって貼り付けが阻止された場合でも、貼り付け操作はアプリケーションの取り消しバッファーに記録されます。その後、(デバイスを振って[元に戻す]を確認することにより)元に戻す操作を実行すると、は、貼り付けたUITextField
と思われる文字列を空の文字列に置き換えようとします。実際には文字列自体に貼り付けられなかったため、これはクラッシュします。存在しない文字列の一部を置き換えようとします。
幸いにも、UITextField
このようにしてが自分自身を殺すのを防ぐことができます。あなたはそれを置き換えることを提案している範囲があることを確認する必要がありません、現在の文字列内に存在します。これは、上記の最初の健全性チェックが行うことです。
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
let str = (textView.text + text)
if str.characters.count <= 10 {
return true
}
textView.text = str.substring(to: str.index(str.startIndex, offsetBy: 10))
return false
}
お役に立てれば幸いです。
return newLength <= 25;
UITextField
iPad iOS 8.1でテストされました。(+1してコメント)。これは最高評価の回答なので、著者はこれについて何か追加しますか?私は編集をしてよかったですが、私のものは定期的に拒否されるようです!:-)
import UIKit
private var kAssociationKeyMaxLength: Int = 0
extension UITextField {
@IBInspectable var maxLength: Int {
get {
if let length = objc_getAssociatedObject(self, &kAssociationKeyMaxLength) as? Int {
return length
} else {
return Int.max
}
}
set {
objc_setAssociatedObject(self, &kAssociationKeyMaxLength, newValue, .OBJC_ASSOCIATION_RETAIN)
addTarget(self, action: #selector(checkMaxLength), for: .editingChanged)
}
}
@objc func checkMaxLength(textField: UITextField) {
guard let prospectiveText = self.text,
prospectiveText.count > maxLength
else {
return
}
let selection = selectedTextRange
let indexEndOfText = prospectiveText.index(prospectiveText.startIndex, offsetBy: maxLength)
let substring = prospectiveText[..<indexEndOfText]
text = String(substring)
selectedTextRange = selection
}
}
編集:メモリリークの問題が修正されました。
8月ありがとう!(投稿)
これは私が最終的に機能するコードです:
#define MAX_LENGTH 20
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if (textField.text.length >= MAX_LENGTH && range.length == 0)
{
return NO; // return NO to not change text
}
else
{return YES;}
}
return textField.text.length < MAX_LENGTH || range.length != 0;
8月の回答を完了するために、提案された関数の可能な実装(UITextFieldのデリゲートを参照)。
私はdomnessコードをテストしませんでしたが、ユーザーが制限に達した場合に動けなくなることはありません。それは、小さい文字列または同等の文字列を置き換える新しい文字列と互換性があります。
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
//limit the size :
int limit = 20;
return !([textField.text length]>limit && [string length] > range.length);
}
これを直接行うことはできませUITextField
ん-maxLength属性がありませんが、UITextField's
デリゲートを設定してから次を使用できます。
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
多くの場合、長さが異なる複数の入力フィールドがあります。
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
int allowedLength;
switch(textField.tag) {
case 1:
allowedLength = MAXLENGTHNAME; // triggered for input fields with tag = 1
break;
case 2:
allowedLength = MAXLENGTHADDRESS; // triggered for input fields with tag = 2
break;
default:
allowedLength = MAXLENGTHDEFAULT; // length default when no tag (=0) value =255
break;
}
if (textField.text.length >= allowedLength && range.length == 0) {
return NO; // Change not allowed
} else {
return YES; // Change allowed
}
}
最善の方法は、テキストの変更に関する通知を設定することです。あなたには-awakeFromNib
あなたのビューコントローラメソッドのあなたがお勧めします:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(limitTextField:) name:@"UITextFieldTextDidChangeNotification" object:myTextField];
次に、同じクラスに次を追加します。
- (void)limitTextField:(NSNotification *)note {
int limit = 20;
if ([[myTextField stringValue] length] > limit) {
[myTextField setStringValue:[[myTextField stringValue] substringToIndex:limit]];
}
}
次に、アウトレットmyTextField
を自分にリンクしますUITextField
。制限に達した後は、それ以上のキャラクターを追加できません。これを必ずdeallocメソッドに追加してください。
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"UITextFieldTextDidChangeNotification" object:myTextField];
私はこの UITextFieldLimitサブクラスを作成しました:
このGitHubリポジトリから、UITextFieldLimit.h
およびUITextFieldLimit.m
そこから取得します。
https://github.com/JonathanGurebo/UITextFieldLimit
そしてテストを開始してください!
ストーリーボードで作成したUITextFieldをマークし、Identity Inspectorを使用してそれを私のサブクラスにリンクします。
次に、それをIBOutletにリンクして制限を設定できます(デフォルトは10)。
ViewController.hファイルには以下を含める必要があります(制限など、設定を変更したくない場合)
#import "UITextFieldLimit.h"
/.../
@property (weak, nonatomic) IBOutlet UITextFieldLimit *textFieldLimit; // <--Your IBOutlet
ViewController.mファイルは@synthesize textFieldLimit
です。
ViewController.mファイルにテキストの長さ制限を設定します。
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[textFieldLimit setLimit:25];// <-- and you won't be able to put more than 25 characters in the TextField.
}
クラスがお役に立てば幸いです。幸運を!
これは問題を解決するのに十分なはずです(4をuの制限で置き換えます)。IBにデリゲートを必ず追加してください。
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
return (newString.length<=4);
}
以下の拡張子を使用して、a UITextField
との最大文字長を設定しUITextView
ます。
Swift 4.0
private var kAssociationKeyMaxLength: Int = 0
private var kAssociationKeyMaxLengthTextView: Int = 0
extension UITextField {
@IBInspectable var maxLength: Int {
get {
if let length = objc_getAssociatedObject(self, &kAssociationKeyMaxLength) as? Int {
return length
} else {
return Int.max
}
}
set {
objc_setAssociatedObject(self, &kAssociationKeyMaxLength, newValue, .OBJC_ASSOCIATION_RETAIN)
addTarget(self, action: #selector(checkMaxLength), for: .editingChanged)
}
}
@objc func checkMaxLength(textField: UITextField) {
guard let prospectiveText = self.text,
prospectiveText.count > maxLength
else {
return
}
let selection = selectedTextRange
let indexEndOfText = prospectiveText.index(prospectiveText.startIndex, offsetBy: maxLength)
let substring = prospectiveText[..<indexEndOfText]
text = String(substring)
selectedTextRange = selection
}
}
extension UITextView:UITextViewDelegate {
@IBInspectable var maxLength: Int {
get {
if let length = objc_getAssociatedObject(self, &kAssociationKeyMaxLengthTextView) as? Int {
return length
} else {
return Int.max
}
}
set {
self.delegate = self
objc_setAssociatedObject(self, &kAssociationKeyMaxLengthTextView, newValue, .OBJC_ASSOCIATION_RETAIN)
}
}
public func textViewDidChange(_ textView: UITextView) {
checkMaxLength(textField: self)
}
@objc func checkMaxLength(textField: UITextView) {
guard let prospectiveText = self.text,
prospectiveText.count > maxLength
else {
return
}
let selection = selectedTextRange
let indexEndOfText = prospectiveText.index(prospectiveText.startIndex, offsetBy: maxLength)
let substring = prospectiveText[..<indexEndOfText]
text = String(substring)
selectedTextRange = selection
}
}
以下の制限を設定できます。
私は、起こりそうな実際の文字列置換をシミュレーションして、その将来の文字列の長さを計算します。
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
if([newString length] > maxLength)
return NO;
return YES;
}
Swift 3バージョン// *****これはSwift 2.xでは機能しません!***** //
最初に新しいSwiftファイル:TextFieldMaxLength.swiftを作成してから、以下のコードを追加します。
import UIKit
private var maxLengths = [UITextField: Int]()
extension UITextField {
@IBInspectable var maxLength: Int {
get {
guard let length = maxLengths[self]
else {
return Int.max
}
return length
}
set {
maxLengths[self] = newValue
addTarget(
self,
action: #selector(limitLength),
for: UIControlEvents.editingChanged
)
}
}
func limitLength(textField: UITextField) {
guard let prospectiveText = textField.text,
prospectiveText.characters.count > maxLength
else {
return
}
let selection = selectedTextRange
let maxCharIndex = prospectiveText.index(prospectiveText.startIndex, offsetBy: maxLength)
text = prospectiveText.substring(to: maxCharIndex)
selectedTextRange = selection
}
}
TextFieldを選択すると、ストーリーボードに新しいフィールド(最大長)が表示されます
さらに質問がある場合は、このリンクを確認してください:http : //www.globalnerdy.com/2016/05/18/ios-programming-trick-how-to-use-xcode-to-set-a-text-fields -maximum-length-visual-studio-style /
Interface Builderを使用すると、任意の関数で「編集が変更されました」のイベントをリンクして取得できます。これで長さを確認できます
- (IBAction)onValueChange:(id)sender
{
NSString *text = nil;
int MAX_LENGTH = 20;
switch ([sender tag] )
{
case 1:
{
text = myEditField.text;
if (MAX_LENGTH < [text length]) {
myEditField.text = [text substringToIndex:MAX_LENGTH];
}
}
break;
default:
break;
}
}
次のコードはsickpの回答に似ていますが、コピーと貼り付けの操作を正しく処理します。制限より長いテキストを貼り付けようとすると、次のコードは、貼り付け操作を完全に拒否する代わりに、制限に合わせてテキストを切り詰めます。
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
static const NSUInteger limit = 70; // we limit to 70 characters
NSUInteger allowedLength = limit - [textField.text length] + range.length;
if (string.length > allowedLength) {
if (string.length > 1) {
// get at least the part of the new string that fits
NSString *limitedString = [string substringToIndex:allowedLength];
NSMutableString *newString = [textField.text mutableCopy];
[newString replaceCharactersInRange:range withString:limitedString];
textField.text = newString;
}
return NO;
} else {
return YES;
}
}
Swiftで最大長を設定するための一般的な解決策があります。IBInspectableを使用すると、Xcode属性インスペクターに新しい属性を追加できます。
import UIKit
private var maxLengths = [UITextField: Int]()
extension UITextField {
@IBInspectable var maxLength: Int {
get {
guard let length = maxLengths[self]
else {
return Int.max
}
return length
}
set {
maxLengths[self] = newValue
addTarget(
self,
action: Selector("limitLength:"),
forControlEvents: UIControlEvents.EditingChanged
)
}
}
func limitLength(textField: UITextField) {
guard let prospectiveText = textField.text
where prospectiveText.characters.count > maxLength else {
return
}
let selection = selectedTextRange
text = prospectiveText.substringWithRange(
Range<String.Index>(prospectiveText.startIndex ..< prospectiveText.startIndex.advancedBy(maxLength))
)
selectedTextRange = selection
}
}
任意の長さの文字列のカットアンドペーストで機能させるには、関数を次のように変更することをお勧めします。
#define MAX_LENGTH 20
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSInteger insertDelta = string.length - range.length;
if (textField.text.length + insertDelta > MAX_LENGTH)
{
return NO; // the new string would be longer than MAX_LENGTH
}
else {
return YES;
}
}
スウィフト4
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
guard let text = textField.text else { return true }
let newLength = text.count + string.count - range.length
return newLength <= 10
}
guard
?
Swift 2.0以降
まず、このプロセスのクラスを作成します。それをStringValidator.swiftと呼びましょう。
次に、その中に次のコードを貼り付けます。
import Foundation
extension String {
func containsCharactersIn(matchCharacters: String) -> Bool {
let characterSet = NSCharacterSet(charactersInString: matchCharacters)
return self.rangeOfCharacterFromSet(characterSet) != nil
}
func containsOnlyCharactersIn(matchCharacters: String) -> Bool {
let disallowedCharacterSet = NSCharacterSet(charactersInString: matchCharacters).invertedSet
return self.rangeOfCharacterFromSet(disallowedCharacterSet) == nil
}
func doesNotContainCharactersIn(matchCharacters: String) -> Bool {
let characterSet = NSCharacterSet(charactersInString: matchCharacters)
return self.rangeOfCharacterFromSet(characterSet) == nil
}
func isNumeric() -> Bool
{
let scanner = NSScanner(string: self)
scanner.locale = NSLocale.currentLocale()
return scanner.scanDecimal(nil) && scanner.atEnd
}
}
クラスを保存します。
使用法..
次に、viewController.swiftクラスに移動して、テキストフィールドのアウトレットを次のように作成します。
@IBOutlet weak var contactEntryTxtFld: UITextField! //First textfield
@IBOutlet weak var contactEntryTxtFld2: UITextField! //Second textfield
次に、テキストフィールドのshouldChangeCharactersInRangeメソッドに移動して、次のように使用します。
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
if string.characters.count == 0 {
return true
}
let latestText = textField.text ?? ""
let checkAbleText = (latestText as NSString).stringByReplacingCharactersInRange(range, withString: string)
switch textField {
case contactEntryTxtFld:
return checkAbleText.containsOnlyCharactersIn("0123456789") && prospectiveText.characters.count <= 5
case contactEntryTxtFld2:
return checkAbleText.containsOnlyCharactersIn("0123456789") && prospectiveText.characters.count <= 5
default:
return true
}
}
テキストフィールドのデリゲートプロトコル/メソッドを設定することを忘れないでください。
これについて説明させてください...私は、別のクラスの内部で記述した文字列の単純な拡張プロセスを使用しています。今、私はチェックと最大値を追加することによってそれらを必要とする別のクラスからそれらの拡張メソッドを呼び出すだけです。
特徴...
タイプ...
containsOnlyCharactersIn //文字のみを受け入れます。
containsCharactersIn //文字の組み合わせを受け入れます
doesNotContainsCharactersIn //文字を受け入れません
これが役に立てば幸い....ありがとう
このコードは、文字数制限を超えて文字列を貼り付ける場合に正常に機能します。
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
let str = (textView.text + text)
if str.characters.count <= 10 {
return true
}
textView.text = str.substring(to: str.index(str.startIndex, offsetBy: 10))
return false
}
投票ありがとうございます。:)
@Frouoに基づいて補足的な回答をします。彼の答えは最も美しい方法だと思います。それは私たちが再利用できる共通のコントロールだからです。
private var kAssociationKeyMaxLength: Int = 0
extension UITextField {
@IBInspectable var maxLength: Int {
get {
if let length = objc_getAssociatedObject(self, &kAssociationKeyMaxLength) as? Int {
return length
} else {
return Int.max
}
}
set {
objc_setAssociatedObject(self, &kAssociationKeyMaxLength, newValue, .OBJC_ASSOCIATION_RETAIN)
self.addTarget(self, action: #selector(checkMaxLength), for: .editingChanged)
}
}
func checkMaxLength(textField: UITextField) {
guard !self.isInputMethod(), let prospectiveText = self.text,
prospectiveText.count > maxLength
else {
return
}
let selection = selectedTextRange
let maxCharIndex = prospectiveText.index(prospectiveText.startIndex, offsetBy: maxLength)
text = prospectiveText.substring(to: maxCharIndex)
selectedTextRange = selection
}
//The method is used to cancel the check when use Chinese Pinyin input method.
//Becuase the alphabet also appears in the textfield when inputting, we should cancel the check.
func isInputMethod() -> Bool {
if let positionRange = self.markedTextRange {
if let _ = self.position(from: positionRange.start, offset: 0) {
return true
}
}
return false
}
}
これは、UITextFieldで最大長を処理する正しい方法です。これにより、リターンキーがテキストフィールドを終了してファーストレスポンダーとして終了し、ユーザーが制限に達したときにユーザーがバックスペースできます。
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
int MAX_LENGHT = 5;
if([string isEqualToString:@"\n"])
{
[textField resignFirstResponder];
return FALSE;
}
else if(textField.text.length > MAX_LENGHT-1)
{
if([string isEqualToString:@""] && range.length == 1)
{
return TRUE;
}
else
{
return FALSE;
}
}
else
{
return TRUE;
}
}
他の回答は、ユーザーがクリップボードから長い文字列を貼り付けることができる場合を処理しません。長い文字列を貼り付けると、切り捨てられるだけで表示されます。これをデリゲートで使用します。
static const NSUInteger maxNoOfCharacters = 5;
-(IBAction)textdidChange:(UITextField * )textField
{
NSString * text = textField.text;
if(text.length > maxNoOfCharacters)
{
text = [text substringWithRange:NSMakeRange(0, maxNoOfCharacters)];
textField.text = text;
}
// use 'text'
}
1行のコードにそれを手に入れました:)
テキストビューのデリゲートを "self"に設定<UITextViewDelegate>
し、.hに次のコードを追加し、.mに次のコードを追加します。数字の "7"を調整して、最大文字数に設定します。
-(BOOL)textView:(UITextView *)a shouldChangeTextInRange:(NSRange)b replacementText:(NSString *)c {
return ((a.text.length+c.length<=7)+(c.length<1)+(b.length>=c.length)>0);
}
このコードは、新しい文字の入力、文字の削除、文字の選択、その後の入力または削除、文字の選択と切り取り、貼り付け、および文字の選択と貼り付けを考慮します。
できた!
または、ビット操作を使用してこのコードを記述する別のクールな方法は、
-(BOOL)textView:(UITextView *)a shouldChangeTextInRange:(NSRange)b replacementText:(NSString *)c {
return 0^((a.text.length+c.length<=7)+(c.length<1)+(b.length>=c.length));
}
私は、UITextFieldサブクラスであるSTATextFieldをオープンソース化しました。STATextFieldは、この機能(およびそれ以上)をそのmaxCharacterLength
プロパティで提供します。
今、あなたは何文字が値を与えたいのか
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSUInteger newLength = [textField.text length] + [string length] - range.length;
return (newLength > 25) ? NO : YES;
}
ここでこのコードを使用します。RESTRICTED_LENGTHは、テキストフィールドに制限する長さです。
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if (textField == nameTF) {
int limit = RESTRICTED_LENGTH - 1;
return !([textField.text length]>limit && [string length] > range.length);
}
else
{
return YES;
}
return NO;
}
テンキーを使用する場合、Swiftでこれを8文字の制限で行いました。
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
return !(textField.text?.characters.count == MAX_LENGTH && string != "")
}
文字列!= ""をテストして、削除ボタンをテンキーで機能させる必要がありました。そうしないと、テキストフィールドが最大値に達した後、テキストフィールドの文字を削除できません。
UITextField拡張機能を実装して、maxLengthプロパティを追加しました。
これはXcode 6のIBInspectablesに基づいているため、Interface BuilderでmaxLength制限を設定できます。
ここに実装があります:
UITextField + MaxLength.h
#import <UIKit/UIKit.h>
@interface UITextField_MaxLength : UITextField<UITextFieldDelegate>
@property (nonatomic)IBInspectable int textMaxLength;
@end
UITextField + MaxLength.m
#import "UITextField+MaxLength.h"
@interface UITextField_MaxLength()
@property (nonatomic, assign) id <UITextFieldDelegate> superDelegate;
@end
@implementation UITextField_MaxLength
- (BOOL)textField:(UITextField *) textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
//validate the length, only if it's set to a non zero value
if (self.textMaxLength>0) {
if(range.length + range.location > textField.text.length)
return NO;
if (textField.text.length+string.length - range.length>self.textMaxLength) {
return NO;
}
}
//if length validation was passed, query the super class to see if the delegate method is implemented there
if (self.superDelegate && [self.superDelegate respondsToSelector:@selector(textField:shouldChangeCharactersInRange:replacementString:)]) {
return [self.superDelegate textField:textField shouldChangeCharactersInRange:range replacementString:string];
}
else{
//if the super class does not implement the delegate method, simply return YES as the length validation was passed
return YES;
}
}
- (void)setDelegate:(id<UITextFieldDelegate>)delegate {
if (delegate == self)
return;
self.superDelegate = delegate;
[super setDelegate:self];
}
//forward all non overriden delegate methods
- (id)forwardingTargetForSelector:(SEL)aSelector {
if ([self.superDelegate respondsToSelector:aSelector])
return self.superDelegate;
return [super forwardingTargetForSelector:aSelector];
}
- (BOOL)respondsToSelector:(SEL)aSelector {
if ([self.superDelegate respondsToSelector:aSelector])
return YES;
return [super respondsToSelector:aSelector];
}
@end