Garis bawahi teks dalam UIButton

143

Adakah yang bisa menyarankan cara untuk menggarisbawahi judul UIButton? Saya memiliki UIButton tipe Kustom, dan saya ingin Judulnya digarisbawahi, tetapi Pembuat Antarmuka tidak memberikan opsi apa pun untuk melakukannya.

Di Pembuat Antarmuka saat Anda memilih Opsi Font untuk Tombol, ini menyediakan opsi untuk memilih Tidak Ada, Tunggal, Ganda, Warna tetapi tidak ada yang memberikan perubahan apa pun pada Judul pada Tombol.

Setiap bantuan dihargai.

RVN
sumber
1
Anda dapat menggunakan UITextView dengan string yang dikaitkan menambahkan tautan ke dalamnya seperti dalam pertanyaan ini stackoverflow.com/questions/21629784/...
Khaled Annajar

Jawaban:

79

UIUnderlinedButton.h

@interface UIUnderlinedButton : UIButton {

}


+ (UIUnderlinedButton*) underlinedButton;
@end

UIDisusunButton.m

@implementation UIUnderlinedButton

+ (UIUnderlinedButton*) underlinedButton {
    UIUnderlinedButton* button = [[UIUnderlinedButton alloc] init];
    return [button autorelease];
}

- (void) drawRect:(CGRect)rect {
    CGRect textRect = self.titleLabel.frame;

    // need to put the line at top of descenders (negative value)
    CGFloat descender = self.titleLabel.font.descender;

    CGContextRef contextRef = UIGraphicsGetCurrentContext();

    // set to same colour as text
    CGContextSetStrokeColorWithColor(contextRef, self.titleLabel.textColor.CGColor);

    CGContextMoveToPoint(contextRef, textRect.origin.x, textRect.origin.y + textRect.size.height + descender);

    CGContextAddLineToPoint(contextRef, textRect.origin.x + textRect.size.width, textRect.origin.y + textRect.size.height + descender);

    CGContextClosePath(contextRef);

    CGContextDrawPath(contextRef, kCGPathStroke);
}


@end
Nick H247
sumber
1
mungkin tidak tepat waktu seperti yang Anda butuhkan!
Nick H247
4
Terima kasih, saya akhirnya menyebutnya sebagai berikut: UIButton * btn = [UIUnderlinedButton buttonWithType: UIButtonTypeCustom];
hb922
2
Kode berfungsi dengan baik, tetapi saya perhatikan garis bawahnya tidak menyusut / tumbuh ketika tampilan berubah ukuran pada rotasi, yang disebabkan oleh drawRecttidak dipanggilnya rotasi. Ini dapat diselesaikan dengan mengatur tombol Anda untuk menggambar ulang seperti itu: myButton.contentMode = UIViewContentModeRedraw;yang memaksa tombol untuk menggambar kembali ketika batas berubah.
AndroidNoob
4
Anda juga dapat mengganti setTitlemetode seperti ini:objective-c - (void)setTitle:(NSString *)title forState:(UIControlState)state { [super setTitle:title forState:state]; [self setNeedsDisplay]; }
Kirualex
379

Untuk menggunakan pembangun antarmuka untuk menggarisbawahi, kita harus:

  • Ubah ke atribut
  • Sorot teks di inspektur Atribut
  • Klik kanan, pilih Font dan kemudian Underline

Garis bawahi menggunakan IB

Video yang dibuat orang lain https://www.youtube.com/watch?v=5-ZnV3jQd9I

finneycanhelp
sumber
2
Pertanyaan bagus @ new2ios Mungkin orang lain tahu
finneycanhelp
1
Saya akan mengajukan pertanyaan baru, @finneycanhelp. Saya harap di Xcode 6.3 akan ada cara yang lebih mudah. Maksud saya mungkin saya dapat mengatur solusi Anda dan kemudian gunakan setTitledengan teks yang dikaitkan. Bagi saya membuat tombol kustom untuk menggambar garis bawah agak eksotis (mungkin saya masih baru untuk iOS walaupun satu App selesai).
new2ios
2
finneydone dibantu! Terima kasih untuk ini! tidak dapat mengetahui mengapa dialog munculan Font tidak berpengaruh. Klik kanan sempurna.
IMFletcher
2
Jawaban yang bagus untuk pengguna Interface Builder untuk hal-hal sederhana semacam ini yang sedikit berfungsi saat dilakukan dalam Kode. Terima kasih! (Y)
Randika Vishman
1
Mengapa pengembang iOS lebih suka menulis kode yang sangat panjang hanya untuk masalah yang sangat sederhana?
mr5
129

Dari iOS6 sekarang mungkin untuk menggunakan NSAttributedString untuk melakukan garis bawah (dan apa pun yang dikaitkan dukungan string) dengan cara yang jauh lebih fleksibel:

NSMutableAttributedString *commentString = [[NSMutableAttributedString alloc] initWithString:@"The Quick Brown Fox"];

[commentString addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInteger:NSUnderlineStyleSingle] range:NSMakeRange(0, [commentString length])];

[button setAttributedTitle:commentString forState:UIControlStateNormal];

Catatan: menambahkan ini sebagai jawaban lain - sebagai solusi yang sama sekali berbeda dengan jawaban saya sebelumnya.

Sunting: anehnya (setidaknya di iOS8) Anda harus menggarisbawahi karakter pertama jika tidak akan berfungsi!

jadi sebagai solusinya, atur char pertama digarisbawahi dengan warna yang jelas!

    // underline Terms and condidtions
    NSMutableAttributedString* tncString = [[NSMutableAttributedString alloc] initWithString:@"View Terms and Conditions"];

    // workaround for bug in UIButton - first char needs to be underlined for some reason!
    [tncString addAttribute:NSUnderlineStyleAttributeName
                      value:@(NSUnderlineStyleSingle)
                      range:(NSRange){0,1}];
    [tncString addAttribute:NSUnderlineColorAttributeName value:[UIColor clearColor] range:NSMakeRange(0, 1)];


    [tncString addAttribute:NSUnderlineStyleAttributeName
                      value:@(NSUnderlineStyleSingle)
                      range:(NSRange){5,[tncString length] - 5}];

    [tncBtn setAttributedTitle:tncString forState:UIControlStateNormal];
Nick H247
sumber
9
Perlu diketahui bahwa ketika Anda melakukannya dengan cara ini, Anda juga harus menambahkan atribut untuk warna, karena teks judul yang dikaitkan tidak akan menggunakan warna yang Anda atur menggunakan setTitleColor: forState:
daveMac
2
Luar biasa, dan terima kasih @daveMac untuk informasi lebih lanjut. Bagi mereka yang tidak tahu atributnya: NSForegroundColorAttributeName
Ryan Crews
dalam metode ini tombol yang digarisbawahi dekat dengan teks metode apa saja untuk mengubah posisi y garis bawah?
Ilesh P
49

Anda dapat melakukannya di pembuat antarmuka itu sendiri.

  1. Pilih pemeriksa atribut
  2. Ubah jenis judul dari biasa menjadi dikaitkan

masukkan deskripsi gambar di sini

  1. Tetapkan ukuran font dan perataan teks yang sesuai

masukkan deskripsi gambar di sini

  1. Kemudian pilih teks judul dan atur font seperti yang digarisbawahi

masukkan deskripsi gambar di sini

Lineesh K Mohan
sumber
28

Ini sangat sederhana dengan string yang dikaitkan

Membuat kamus dengan atribut yang ditetapkan dan berlaku untuk string yang dikaitkan. Kemudian Anda dapat mengatur string yang dikaitkan sebagai attibutedtitle di uibutton atau attributedtext di uilabel.

NSDictionary *attrDict = @{NSFontAttributeName : [UIFont
 systemFontOfSize:14.0],NSForegroundColorAttributeName : [UIColor
 whiteColor]};
 NSMutableAttributedString *title =[[NSMutableAttributedString alloc] initWithString:@"mybutton" attributes: attrDict]; 
[title addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInteger:NSUnderlineStyleSingle] range:NSMakeRange(0,[commentString length])]; [btnRegLater setAttributedTitle:title forState:UIControlStateNormal];
Rinku
sumber
Apa commentString; apakah Anda menyalin dari jawaban @ NickH247?
maknanya penting
21

Inilah fungsi saya, berfungsi di Swift 1.2.

func underlineButton(button : UIButton, text: String) {

    var titleString : NSMutableAttributedString = NSMutableAttributedString(string: text)
    titleString.addAttribute(NSUnderlineStyleAttributeName, value: NSUnderlineStyle.StyleSingle.rawValue, range: NSMakeRange(0, count(text.utf8)))
    button.setAttributedTitle(titleString, forState: .Normal)
}

Ekstensi UPDATE Swift 3.0:

extension UIButton {
    func underlineButton(text: String) {
        let titleString = NSMutableAttributedString(string: text)
        titleString.addAttribute(NSUnderlineStyleAttributeName, value: NSUnderlineStyle.styleSingle.rawValue, range: NSMakeRange(0, text.characters.count))
        self.setAttributedTitle(titleString, for: .normal)
    }
}
Adam Studenic
sumber
13

Jawaban Nick adalah cara yang hebat dan cepat untuk melakukan ini.

Saya menambahkan dukungan drawRectuntuk bayangan.

Jawaban Nick tidak memperhitungkan jika judul tombol Anda memiliki bayangan di bawah teks:

masukkan deskripsi gambar di sini

Tetapi Anda dapat memindahkan garis bawah ke bawah dengan ketinggian bayangan seperti ini:

CGFloat descender = self.titleLabel.font.descender;
CGContextRef contextRef = UIGraphicsGetCurrentContext();
CGFloat shadowHeight = self.titleLabel.shadowOffset.height;
descender += shadowHeight;

Maka Anda akan mendapatkan sesuatu seperti ini:

masukkan deskripsi gambar di sini

annie
sumber
self.titleLabel.font.descender; ini telah disusutkan di iOS 3.0
RAJA
5

Untuk Swift 3 ekstensi berikut dapat digunakan:

extension UIButton {
    func underlineButton(text: String) {
        let titleString = NSMutableAttributedString(string: text)
        titleString.addAttribute(NSUnderlineStyleAttributeName, value: NSUnderlineStyle.styleSingle.rawValue, range: NSMakeRange(0, text.characters.count))
        self.setAttributedTitle(titleString, for: .normal)
    }
}
Durga Vundavalli
sumber
4
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
CGRect textRect = self.titleLabel.frame;

// need to put the line at top of descenders (negative value)
CGFloat descender = self.titleLabel.font.descender;

CGContextRef contextRef = UIGraphicsGetCurrentContext();
UIColor *colr;
// set to same colour as text
if (self.isHighlighted || self.isSelected) {
    colr=self.titleLabel.highlightedTextColor;
}
else{
    colr= self.titleLabel.textColor;
}
CGContextSetStrokeColorWithColor(contextRef, colr.CGColor);

CGContextMoveToPoint(contextRef, textRect.origin.x, textRect.origin.y +        textRect.size.height + descender);

CGContextAddLineToPoint(contextRef, textRect.origin.x + textRect.size.width, textRect.origin.y + textRect.size.height + descender);

CGContextClosePath(contextRef);

CGContextDrawPath(contextRef, kCGPathStroke);
}
//Override this to change the underline color to highlighted color
-(void)setHighlighted:(BOOL)highlighted
{
[super setHighlighted:highlighted];
// [self setNeedsDisplay];
}
Rohit
sumber
3

Memperluas jawaban oleh @Nick H247, saya mengalami masalah ketika awalnya garis bawahnya tidak digambar ulang ketika tombol diubah ukurannya pada rotasi; ini dapat diselesaikan dengan mengatur tombol Anda untuk menggambar kembali seperti:

myButton.contentMode = UIViewContentModeRedraw; 

Ini memaksa tombol untuk menggambar ulang ketika batas berubah.

Kedua, kode asli mengasumsikan Anda hanya memiliki 1 baris teks di tombol (tombol saya membungkus 2 baris pada rotasi) dan garis bawah hanya muncul pada baris terakhir teks. Kode drawRect dapat dimodifikasi untuk menghitung terlebih dahulu jumlah baris di tombol, kemudian meletakkan garis bawah pada setiap baris daripada hanya bagian bawah, seperti:

 - (void) drawRect:(CGRect)rect {
CGRect textRect = self.titleLabel.frame;

// need to put the line at top of descenders (negative value)
CGFloat descender = self.titleLabel.font.descender;

CGContextRef contextRef = UIGraphicsGetCurrentContext();

// set to same colour as text
CGContextSetStrokeColorWithColor(contextRef, self.titleLabel.textColor.CGColor);

CGSize labelSize = [self.titleLabel.text sizeWithFont:self.titleLabel.font
                            constrainedToSize:self.titleLabel.frame.size
                                lineBreakMode:UILineBreakModeWordWrap];

CGSize labelSizeNoWrap = [self.titleLabel.text sizeWithFont:self.titleLabel.font forWidth:self.titleLabel.frame.size.width lineBreakMode:UILineBreakModeMiddleTruncation ];

int numberOfLines = abs(labelSize.height/labelSizeNoWrap.height);

for(int i = 1; i<=numberOfLines;i++) {
 //        Original code
 //        CGContextMoveToPoint(contextRef, textRect.origin.x, textRect.origin.y + textRect.size.height + descender + PADDING);
 //        
 //        CGContextAddLineToPoint(contextRef, textRect.origin.x + textRect.size.width, textRect.origin.y + textRect.size.height + descender);

    CGContextMoveToPoint(contextRef, textRect.origin.x, textRect.origin.y + (labelSizeNoWrap.height*i) + descender + PADDING);

    CGContextAddLineToPoint(contextRef, textRect.origin.x + textRect.size.width, textRect.origin.y + (labelSizeNoWrap.height*i) + descender);

    CGContextClosePath(contextRef);

    CGContextDrawPath(contextRef, kCGPathStroke);

}


}

Semoga kode ini membantu orang lain!

AndroidNoob
sumber
3

Dengan cepat

func underlineButton(button : UIButton) {

var titleString : NSMutableAttributedString = NSMutableAttributedString(string: button.titleLabel!.text!)
titleString.addAttribute(NSUnderlineStyleAttributeName, value: NSUnderlineStyle.StyleSingle.rawValue, range: NSMakeRange(0, button.titleLabel!.text!.utf16Count))
button.setAttributedTitle(titleString, forState: .Normal)}
Arshad
sumber
3

Anda dapat menggunakan kode ini untuk menambahkan garis bawah dengan tombol spasi di.

  • Ketika saya mencoba menggambar garis bawah dari pembangun antarmuka. Ini terlihat seperti gambar di bawah ini.

1 - Referensi pembangun antarmuka

masukkan deskripsi gambar di sini

  • Dan setelah menggunakan kode di bawah ini saya mencapai hasil yang saya inginkan.

2 - menggunakan kode yang dijelaskan

masukkan deskripsi gambar di sini

public func setTextUnderline()
    {
        let dummyButton: UIButton = UIButton.init()
        dummyButton.setTitle(self.titleLabel?.text, for: .normal)
        dummyButton.titleLabel?.font = self.titleLabel?.font
        dummyButton.sizeToFit()

        let dummyHeight = dummyButton.frame.size.height + 3

        let bottomLine = CALayer()
        bottomLine.frame = CGRect.init(x: (self.frame.size.width - dummyButton.frame.size.width)/2, y: -(self.frame.size.height - dummyHeight), width: dummyButton.frame.size.width, height: 1.0)
        bottomLine.backgroundColor = self.titleLabel?.textColor.cgColor
        self.layer.addSublayer(bottomLine)
    }
Ayaz Rafai
sumber
Terima kasih atas cuplikan kode ini, yang mungkin memberikan bantuan terbatas dan segera. Penjelasan yang tepat akan sangat meningkatkan nilai jangka panjangnya dengan menunjukkan mengapa ini adalah solusi yang baik untuk masalah ini, dan akan membuatnya lebih bermanfaat bagi pembaca masa depan dengan pertanyaan lain yang serupa. Harap edit jawaban Anda untuk menambahkan beberapa penjelasan, termasuk asumsi yang Anda buat.
Toby Speight
3

Versi Swift 5.0 yang bekerja pada September 2019 di Xcode 10.3:

extension UIButton {
  func underlineText() {
    guard let title = title(for: .normal) else { return }

    let titleString = NSMutableAttributedString(string: title)
    titleString.addAttribute(
      .underlineStyle,
      value: NSUnderlineStyle.single.rawValue,
      range: NSRange(location: 0, length: title.count)
    )
    setAttributedTitle(titleString, for: .normal)
  }
}

Untuk menggunakannya, atur judul tombol Anda terlebih dahulu button.setTitle("Button Title", for: .normal)lalu panggil button.underlineText()untuk membuat judul itu digarisbawahi.

Max Desiatov
sumber
1
Saya dapat mengonfirmasi ini berfungsi pada versi yang setua iOS 10.3.1, Xcode 10.3 tidak mendukung simulator yang lebih lama dari pada Mojave, sejauh yang saya ketahui.
Max Desiatov
2

Bagaimana kita menangani kasing ketika kita menekan tombol bergaris bawah? Dalam hal itu warna teks tombol berubah sesuai dengan warna yang disorot tetapi garis tetap warna asli. Katakanlah jika warna teks tombol dalam keadaan normal adalah hitam maka garis bawahnya juga akan memiliki warna hitam. Warna yang disorot tombol adalah putih. Tekan terus tombol mengubah warna teks tombol dari hitam ke putih tetapi warna garis bawah tetap hitam.

Parvez Qureshi
sumber
2
Anda dapat menguji apakah tombolnya disorot dan atau dipilih, dan atur warnanya. tidak yakin apakah redraw akan diminta secara otomatis, jika tidak Anda perlu mengganti setSelected / setHighlighted dan memanggil super dan [self setNeedsDisplay]
Nick H247
2

Saya percaya ini adalah beberapa bug pada editor font di XCode. Jika Anda menggunakan pembangun antarmuka, Anda harus mengubah judul dari Plain ke Attributed, buka TextEdit buat teks yang digarisbawahi dan salin-tempel ke kotak teks di XCode

dangh
sumber
2

Jawaban Nick H247 tetapi pendekatan Swift:

import UIKit

class UnderlineUIButton: UIButton {

    override func drawRect(rect: CGRect) {
        super.drawRect(rect)

        let textRect = self.titleLabel!.frame

        var descender = self.titleLabel?.font.descender

        var contextRef: CGContextRef = UIGraphicsGetCurrentContext();

        CGContextSetStrokeColorWithColor(contextRef, self.titleLabel?.textColor.CGColor);

        CGContextMoveToPoint(contextRef, textRect.origin.x, textRect.origin.y + textRect.size.height + descender!);

        CGContextAddLineToPoint(contextRef, textRect.origin.x + textRect.size.width, textRect.origin.y + textRect.size.height + descender!);

        CGContextClosePath(contextRef);

        CGContextDrawPath(contextRef, kCGPathStroke);
    }
}
el.severo
sumber
2
func underline(text: String, state: UIControlState = .normal, color:UIColor? = nil) {
        var titleString = NSMutableAttributedString(string: text)

        if let color = color {
            titleString = NSMutableAttributedString(string: text,
                               attributes: [NSForegroundColorAttributeName: color])
        }

        let stringRange = NSMakeRange(0, text.characters.count)
        titleString.addAttribute(NSUnderlineStyleAttributeName,
                                 value: NSUnderlineStyle.styleSingle.rawValue,
                                 range: stringRange)

        self.setAttributedTitle(titleString, for: state)
    }
LuAndre
sumber
1

Versi Swift 3 untuk jawaban @ NickH247 dengan warna garis bawah kustom, linewidth dan celah:

import Foundation

class UnderlinedButton: UIButton {

    private let underlineColor: UIColor
    private let thickness: CGFloat
    private let gap: CGFloat

    init(underlineColor: UIColor, thickness: CGFloat, gap: CGFloat, frame: CGRect? = nil) {
        self.underlineColor = underlineColor
        self.thickness = thickness
        self.gap = gap
        super.init(frame: frame ?? .zero)
    }

    override func draw(_ rect: CGRect) {
        super.draw(rect)

        guard let textRect = titleLabel?.frame,
            let decender = titleLabel?.font.descender,
            let context = UIGraphicsGetCurrentContext() else { return }

        context.setStrokeColor(underlineColor.cgColor)
        context.move(to: CGPoint(x: textRect.origin.x, y: textRect.origin.y + textRect.height + decender + gap))
        context.setLineWidth(thickness)
        context.addLine(to: CGPoint(x: textRect.origin.x + textRect.width, y: textRect.origin.y + textRect.height + decender + gap))
        context.closePath()
        context.drawPath(using: .stroke)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}
bughana
sumber