UIButtonに複数行のテキストを追加するにはどうすればよいですか?
-
03-07-2019 - |
質問
次のコードがあります...
UILabel *buttonLabel = [[UILabel alloc] initWithFrame:targetButton.bounds];
buttonLabel.text = @"Long text string";
[targetButton addSubview:buttonLabel];
[targetButton bringSubviewToFront:buttonLabel];
...ボタンに複数行のテキストを含めることができるという考えですが、テキストは常にUIButtonのbackgroundImageによって隠されています。ボタンのサブビューを表示するロギング呼び出しは、UILabelが追加されていることを示していますが、テキスト自体は表示されていません。これはUIButtonのバグですか、何か間違っていますか?
解決
iOS 6以降では、次を使用して複数の行を許可します。
button.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
// you probably want to center it
button.titleLabel.textAlignment = NSTextAlignmentCenter; // if you want to
[button setTitle: @"Line1\nLine2" forState: UIControlStateNormal];
iOS 5以下では、次を使用して複数の行を許可します。
button.titleLabel.lineBreakMode = UILineBreakModeWordWrap;
// you probably want to center it
button.titleLabel.textAlignment = UITextAlignmentCenter;
[button setTitle: @"Line1\nLine2" forState: UIControlStateNormal];
2017、iOS9以降の場合、
一般的には、次の2つのことを行います。
- "属性付きテキスト"を選択
- "改行"ポップアップで"ワードラップ" を選択します
他のヒント
選択された答えは正しいですが、Interface Builderでこのようなことをしたい場合は、これを行うことができます:
複数の行を中心にタイトルを付けてボタンを追加する場合は、ボタンのInterface Builderの設定を設定します。
[]
IOS 6の場合:
button.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
button.titleLabel.textAlignment = NSTextAlignmentCenter;
As
UILineBreakModeWordWrap and UITextAlignmentCenter
IOS 6以降では非推奨です。.
ロジャー・ノーランの提案を再言するが、明示的なコードでは、これが一般的な解決策です。
button.titleLabel?.numberOfLines = 0
SWIFT 3
button.titleLabel?.lineBreakMode = .byWordWrapping
button.titleLabel?.textAlignment = .center
button.setTitle("Button\nTitle",for: .normal)
もっと簡単な方法があります:
someButton.lineBreakMode = UILineBreakModeWordWrap;
(iOS 3以降の編集:)
someButton.titleLabel.lineBreakMode = UILineBreakModeWordWrap;
iOS7で自動レイアウトを使用して左揃え:
button.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
button.titleLabel.textAlignment = NSTextAlignmentLeft;
button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
まず、UIButtonには既にUILabelが含まれていることに注意する必要があります。 – setTitle:forState:
を使用して設定できます。
この例の問題は、UILabelの numberOfLines
プロパティをデフォルト値の1以外に設定する必要があることです。 lineBreakMode
プロパティも確認する必要があります。
Xcode 4のストーリーボードを使用している場合は、ボタンをクリックし、右側の[ユーティリティ]ペインの[属性インスペクター]に、改行のオプションが表示されます。ワードラップを選択すれば、準備完了です。
ここでの回答は、プログラムで複数行ボタンタイトルを実現する方法を示しています。
ストーリーボードを使用している場合は、[Ctrl + Enter]を入力してボタンのタイトルフィールドに強制的に改行を追加できることを追加しました。
HTH
このコードを追加する必要があります:
buttonLabel.titleLabel.numberOfLines = 0;
タイトルUILabelを兄弟ビューとするというブレントのアイデアに関しては、私にはあまり良いアイデアとは思えません。タッチイベントがUIButtonのビューを通過しないため、UILabelとの相互作用の問題を考え続けます。
一方で、UIButtonをUIButtonのサブビューとして使用すると、タッチイベントが常にUILabelのスーパービューに伝播されることを知って非常に快適です。
私はこのアプローチを取りましたが、backgroundImageで報告された問題に気付きませんでした。 UIButtonサブクラスの-titleRectForContentRect:にこのコードを追加しましたが、UIButtonスーパービューの描画ルーチンにコードを配置することもできます。その場合、selfへのすべての参照をUIButtonの変数に置き換えます。
#define TITLE_LABEL_TAG 1234
- (CGRect)titleRectForContentRect:(CGRect)rect
{
// define the desired title inset margins based on the whole rect and its padding
UIEdgeInsets padding = [self titleEdgeInsets];
CGRect titleRect = CGRectMake(rect.origin.x + padding.left,
rect.origin.x + padding.top,
rect.size.width - (padding.right + padding.left),
rect.size.height - (padding.bottom + padding].top));
// save the current title view appearance
NSString *title = [self currentTitle];
UIColor *titleColor = [self currentTitleColor];
UIColor *titleShadowColor = [self currentTitleShadowColor];
// we only want to add our custom label once; only 1st pass shall return nil
UILabel *titleLabel = (UILabel*)[self viewWithTag:TITLE_LABEL_TAG];
if (!titleLabel)
{
// no custom label found (1st pass), we will be creating & adding it as subview
titleLabel = [[UILabel alloc] initWithFrame:titleRect];
[titleLabel setTag:TITLE_LABEL_TAG];
// make it multi-line
[titleLabel setNumberOfLines:0];
[titleLabel setLineBreakMode:UILineBreakModeWordWrap];
// title appearance setup; be at will to modify
[titleLabel setBackgroundColor:[UIColor clearColor]];
[titleLabel setFont:[self font]];
[titleLabel setShadowOffset:CGSizeMake(0, 1)];
[titleLabel setTextAlignment:UITextAlignmentCenter];
[self addSubview:titleLabel];
[titleLabel release];
}
// finally, put our label in original title view's state
[titleLabel setText:title];
[titleLabel setTextColor:titleColor];
[titleLabel setShadowColor:titleShadowColor];
// and return empty rect so that the original title view is hidden
return CGRectZero;
}
時間をかけて、このことについてもう少し書いたこちら。そこには、より短いソリューションも示していますが、すべてのシナリオに完全に適合するわけではなく、いくつかのプライベートビューのハッキングが含まれています。また、すぐに使用できるUIButtonサブクラスをダウンロードできます。
iOS 6で自動レイアウトを使用する場合、 preferredMaxLayoutWidth
プロパティも設定する必要がある場合があります。
button.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
button.titleLabel.textAlignment = NSTextAlignmentCenter;
button.titleLabel.preferredMaxLayoutWidth = button.frame.size.width;
完全に動作します。
Plistなどの構成ファイルでこれを使用するには、次のように、CDATAを使用して複数行タイトルを書き込む必要があります。
<string><![CDATA[Line1
Line2]]></string>
lineBreakModeをNSLineBreakByWordWrapping(IBまたはコードのいずれか)に設定すると、ボタンラベルが複数行になりますが、ボタンのフレームには影響しません。
ボタンに動的タイトルがある場合、1つのトリックがあります。同じフォントで非表示のUILabelを配置し、レイアウトでボタンの高さにその高さを結び付けます。ボタンとラベルにテキストを設定すると、自動レイアウトがすべての作業を行います。
注
1行ボタンの本来のサイズの高さはラベルの高さよりも大きいため、ラベルの高さの縮小を防ぐために、垂直方向のコンテンツのハグの優先度はボタンの垂直方向のコンテンツの圧縮抵抗よりも大きくなければなりません。
自動レイアウトを使用する場合。
button.titleLabel?.adjustsFontSizeToFitWidth = true
button.titleLabel?.numberOfLines = 2
複数行を有効にした後、自動レイアウトで問題が発生しました:
titleLabel
のサイズはボタンのサイズに影響しません
contentEdgeInsets
に基づいて Constraints
を追加しました(この場合、contentEdgeInsetsは(10、10、10、10)
makeMultiLineSupport()
:
を呼び出した後
それがあなたを助けることを願っています(swift 5.0):
extension UIButton {
func makeMultiLineSupport() {
guard let titleLabel = titleLabel else {
return
}
titleLabel.numberOfLines = 0
titleLabel.setContentHuggingPriority(.required, for: .vertical)
titleLabel.setContentHuggingPriority(.required, for: .horizontal)
addConstraints([
.init(item: titleLabel,
attribute: .top,
relatedBy: .greaterThanOrEqual,
toItem: self,
attribute: .top,
multiplier: 1.0,
constant: contentEdgeInsets.top),
.init(item: titleLabel,
attribute: .bottom,
relatedBy: .greaterThanOrEqual,
toItem: self,
attribute: .bottom,
multiplier: 1.0,
constant: contentEdgeInsets.bottom),
.init(item: titleLabel,
attribute: .left,
relatedBy: .greaterThanOrEqual,
toItem: self,
attribute: .left,
multiplier: 1.0,
constant: contentEdgeInsets.left),
.init(item: titleLabel,
attribute: .right,
relatedBy: .greaterThanOrEqual,
toItem: self,
attribute: .right,
multiplier: 1.0,
constant: contentEdgeInsets.right)
])
}
}
最近、このようなことをインターフェースビルダーでケースバイケースでアクセス可能にする必要がある場合は、次のような簡単な拡張機能でそれを行うことができます:
extension UIButton {
@IBInspectable var numberOfLines: Int {
get { return titleLabel?.numberOfLines ?? 1 }
set { titleLabel?.numberOfLines = newValue }
}
}
その後、ラベルのように、任意のUIButtonまたはUIButtonサブクラスの属性としてnumberOfLinesを設定できます。ビューのレイヤーの角の半径や、投影するシャドウの属性など、他の通常はアクセスできない値のホスト全体についても同じことが言えます。
独自のボタンクラスをロールします。長期的に見て、これが断然最高のソリューションです。 UIButtonおよび他のUIKitクラスは、カスタマイズ方法が非常に制限されています。
self.btnError.titleLabel?.lineBreakMode = NSLineBreakMode.byWordWrapping
self.btnError.titleLabel?.textAlignment = .center
self.btnError.setTitle("Title", for: .normal)
swift 4.0
btn.titleLabel?.lineBreakMode = .byWordWrapping
btn.titleLabel?.textAlignment = .center
btn.setTitle( "Line1\nLine2", for: .normal)
jessecurryの回答を STAButton は STAControls オープンソースライブラリ。現在、開発中のアプリの1つで使用しており、ニーズに合っています。改善方法やプルリクエストの送信方法については、お気軽にお問い合わせください。
Swift 5.0 および Xcode 10.2
の場合SharedClass の例は1回書くだけですべてのウェアを使用します
これは共有クラスです(このように、すべてのコンポーネントプロパティを使用します)
import UIKit
class SharedClass: NSObject {
static let sharedInstance = SharedClass()
private override init() {
}
}
//UIButton extension
extension UIButton {
//UIButton properties
func btnMultipleLines() {
titleLabel?.numberOfLines = 0
titleLabel?.lineBreakMode = .byWordWrapping
titleLabel?.textAlignment = .center
}
}
ViewController 呼び出しで次のようにします
button.btnMultipleLines()//This is your button
コントロールにサブビューを追加しても問題ありませんが、実際に機能する保証はありません。コントロールがそこにあると予期しないため、動作が不十分になる可能性があるためです。うまく行けば、ボタンの兄弟ビューとしてラベルを追加し、ボタンと重なるようにフレームを設定します。ボタンの上に表示されるように設定されている限り、ボタンでできることは何もありません。
言い換えれば:
[button.superview addSubview:myLabel];
myLabel.center = button.center;