Добавьте нижнюю строку для просмотра в Swift / Objective C / Xamarin

128

Я хотел бы сохранить границу в нижней части только в UITextField. Но я не знаю, как мы можем держать это на нижней стороне.

Можете ли вы посоветовать мне?

Теги:
xamarin
uitextfield

15 ответов

290
Лучший ответ

Новый подход: (рекомендуется)

В конце концов, я нашел еще один способ сделать это, это более просто и удобно. Но единственное условие - UITextField должен содержать автоматический макет.

Я использую язык визуального форматирования (VFL) здесь, это позволит добавить строку в любой UIControl.

Вспомогательный метод:

Вы можете добавить этот вспомогательный метод в свой глобальный вспомогательный класс (я использовал метод глобального класса) или в том же контроллере представления (используя метод экземпляра).

typedef enum : NSUInteger {
    LINE_POSITION_TOP,
    LINE_POSITION_BOTTOM
} LINE_POSITION;


- (void) addLineToView:(UIView *)view atPosition:(LINE_POSITION)position withColor:(UIColor *)color lineWitdh:(CGFloat)width {
    // Add line
    UIView *lineView = [[UIView alloc] init];
    [lineView setBackgroundColor:color];
    [lineView setTranslatesAutoresizingMaskIntoConstraints:NO];
    [view addSubview:lineView];

    NSDictionary *metrics = @{@"width" : [NSNumber numberWithFloat:width]};
    NSDictionary *views = @{@"lineView" : lineView};
    [view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[lineView]|" options: 0 metrics:metrics views:views]];

    switch (position) {
        case LINE_POSITION_TOP:
            [view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[lineView(width)]" options: 0 metrics:metrics views:views]];
            break;

        case LINE_POSITION_BOTTOM:
            [view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[lineView(width)]|" options: 0 metrics:metrics views:views]];
            break;
        default: break;
    }
}

Использование:

[self addLineToView:self.textField atPosition:LINE_POSITION_TOP withColor:[UIColor darkGrayColor] lineWitdh:0.5];

Используя Swift:

Вспомогательный метод:

enum LINE_POSITION {
    case LINE_POSITION_TOP
    case LINE_POSITION_BOTTOM
}

func addLineToView(view : UIView, position : LINE_POSITION, color: UIColor, width: Double) {
        let lineView = UIView()
        lineView.backgroundColor = color
        lineView.translatesAutoresizingMaskIntoConstraints = false // This is important!
        view.addSubview(lineView)

        let metrics = ["width" : NSNumber(value: width)]
        let views = ["lineView" : lineView]
        view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[lineView]|", options:NSLayoutFormatOptions(rawValue: 0), metrics:metrics, views:views))

        switch position {
        case .LINE_POSITION_TOP:
            view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[lineView(width)]", options:NSLayoutFormatOptions(rawValue: 0), metrics:metrics, views:views))
            break
        case .LINE_POSITION_BOTTOM:
            view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[lineView(width)]|", options:NSLayoutFormatOptions(rawValue: 0), metrics:metrics, views:views))
            break
        default:
            break
        }
    }

Использование:

self.addLineToView(view: textField, position:.LINE_POSITION_BOTTOM, color: UIColor.darkGray, width: 0.5)

Старый подход:

Этот ответ будет отлично работать, если вы создадите объект UITextField программно.

Примечание. Если объект UITextField создан в раскадровке, установите для его свойства " Border Style значение " None в инспекторе атрибутов раскадровки.

Следующая переменная textField является объектом UITextField управления UITextField в котором будет установлена нижняя граница.

Свифт код:

let border = CALayer()
let width = CGFloat(2.0)
border.borderColor = UIColor.darkGray.cgColor
border.frame = CGRect(x: 0, y: textField.frame.size.height - width, width: textField.frame.size.width, height: textField.frame.size.height)

border.borderWidth = width
textField.layer.addSublayer(border)
textField.layer.masksToBounds = true

Objective C Code:

CALayer *border = [CALayer layer];
CGFloat borderWidth = 2;
border.borderColor = [UIColor darkGrayColor].CGColor;
border.frame = CGRectMake(0, textField.frame.size.height - borderWidth, textField.frame.size.width, textField.frame.size.height);
border.borderWidth = borderWidth;
[textField.layer addSublayer:border];
textField.layer.masksToBounds = YES;

Xamarin код:

 var border = new CALayer();
 nfloat width = 2;
 border.BorderColor = UIColor.Black.CGColor;
 border.Frame = new CoreGraphics.CGRect(0, textField.Frame.Size.Height - width, textField.Frame.Size.Width, textField.Frame.Size.Height);
 border.BorderWidth = width;
 textField.Layer.AddSublayer(border);
 textField.Layer.MasksToBounds = true;

У многих пользователей была проблема с автоматическим макетом, а некоторые люди не могли отобразить границу UITextField. Вот решение:


Если вы напишете код ниже в viewDidLoad(), тогда вы не получите фрейм для textField, поэтому граница не будет отображаться правильно.

Чтобы получить правильный кадр для границы, переопределите viewDidLayoutSubviews() и напишите в нем код.

viewDidLayoutSubviews() после загрузки всех представлений в представление.

Не забывайте, что этот метод вызывается несколько раз и не является частью жизненного цикла ViewController, поэтому будьте осторожны при его использовании.

  • 0
    спасибо kampai, я добавил этот код, но он дает мне ошибки ниже в моем файле swift. /Users/imriel/Documents/Workspace/ContatApp/ContatApp/ViewController.swift:30:16: последовательные операторы в строке должны быть разделены знаком ';' Есть ли у вас какие-либо идеи, как это можно решить. Извините, что беспокою вас снова ..
  • 0
    @dhavalshah: добавлен код для swift
Показать ещё 24 комментария
131

Если вы хотите обойтись без предварительного знания фреймов, без создания подклассов и без автоматического размещения:

Swift 4.x/Swift 3.x

extension UITextField {
  func setBottomBorder() {
    self.borderStyle = .none
    self.layer.backgroundColor = UIColor.white.cgColor

    self.layer.masksToBounds = false
    self.layer.shadowColor = UIColor.gray.cgColor
    self.layer.shadowOffset = CGSize(width: 0.0, height: 1.0)
    self.layer.shadowOpacity = 1.0
    self.layer.shadowRadius = 0.0
  }
}

Вызовите yourTextField.setBottomBorder() из любого места, не убедившись, что кадры правильные.

Результат выглядит так:

Изображение 1889

  • 0
    Это действительно работает? Я не получаю никакой прибыли
  • 1
    Это работает для меня, можете ли вы показать свой код, чтобы мы могли посмотреть на
Показать ещё 10 комментариев
38

Вы можете создать подкласс UITextField, как показано ниже:

class TextField : UITextField {

    override var tintColor: UIColor! {

        didSet {
            setNeedsDisplay()
        }
    }

    override func draw(_ rect: CGRect) {

        let startingPoint   = CGPoint(x: rect.minX, y: rect.maxY)
        let endingPoint     = CGPoint(x: rect.maxX, y: rect.maxY)

        let path = UIBezierPath()

        path.move(to: startingPoint)
        path.addLine(to: endingPoint)
        path.lineWidth = 2.0

        tintColor.setStroke()

        path.stroke()
    }
}
  • 0
    Лучший подход. Я просто хотел узнать, как изменить цвет подчеркивания во время редактирования или во время метода didBeginEditing и изменить цвет на didEndEditing
  • 0
    Смотрите обновленный ответ, установите tintColor в didBeginEditing и didEndEditing
Показать ещё 1 комментарий
19

Ни одно из этих решений не оправдало моих ожиданий. Я хотел подкласс TextField, так как я не хочу постоянно устанавливать границу вручную. Я также хотел изменить цвет рамки, например. для ошибки. Итак, вот мое решение с Anchors:

class CustomTextField: UITextField {

    var bottomBorder = UIView()

    override func awakeFromNib() {

            // Setup Bottom-Border

            self.translatesAutoresizingMaskIntoConstraints = false

            bottomBorder = UIView.init(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
            bottomBorder.backgroundColor = UIColor(rgb: 0xE2DCD1) // Set Border-Color
            bottomBorder.translatesAutoresizingMaskIntoConstraints = false

            addSubview(bottomBorder)

            bottomBorder.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
            bottomBorder.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
            bottomBorder.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
            bottomBorder.heightAnchor.constraint(equalToConstant: 1).isActive = true // Set Border-Strength

    }
}

---- Дополнительно ----

Чтобы изменить цвет, добавьте sth, как это, в CustomTextField Class:

@IBInspectable var hasError: Bool = false {
    didSet {

        if (hasError) {

            bottomBorder.backgroundColor = UIColor.red

        } else {

            bottomBorder.backgroundColor = UIColor(rgb: 0xE2DCD1)

        }

    }
}

И чтобы вызвать вызов Error после этого после создания экземпляра CustomTextField

textField.hasError = !textField.hasError

Изображение 1890

Надеюсь, это поможет кому-то;)

  • 2
    Лучшее решение на данный момент, вы даже можете изменить его для других состояний "проверки"
19
 extension UITextField {  
  func setBottomBorder(color:String) {
    self.borderStyle = UITextBorderStyle.None
    let border = CALayer()
    let width = CGFloat(1.0)
    border.borderColor = UIColor(hexString: color)!.cgColor
    border.frame = CGRect(x: 0, y: self.frame.size.height - width,   width:  self.frame.size.width, height: self.frame.size.height)
    border.borderWidth = width
    self.layer.addSublayer(border)
    self.layer.masksToBounds = true
   }
}

а затем просто сделайте это:

yourTextField.setBottomBorder(color: "#3EFE46")
  • 2
    Я думал сделать так, но если мы используем это в viewDidLoad() , кадр будет неправильным. Таким образом, у нас есть 2 варианта: viewDidLayoutSubviews() или viewDidAppear() . Но viewDidLayoutSubviews() несколько раз и вызывается из viewDidAppear() не будет хорошим опытом.
  • 0
    viewDidLayoutSubviews() также не будет работать, если текстовое поле вложено в multiple View . Вы получите несколько шире.
10

Вы можете создать это расширение вне класса и заменить ширину любой границей, которую вы хотите.

Swift 4

extension UITextField
{
    func setBottomBorder(withColor color: UIColor)
    {
        self.borderStyle = UITextBorderStyle.none
        self.backgroundColor = UIColor.clear
        let width: CGFloat = 1.0

        let borderLine = UIView(frame: CGRect(x: 0, y: self.frame.height - width, width: self.frame.width, height: width))
        borderLine.backgroundColor = color
        self.addSubview(borderLine)
    }
}

оригинал

extension UITextField
{
    func setBottomBorder(borderColor: UIColor)
    {
        self.borderStyle = UITextBorderStyle.None
        self.backgroundColor = UIColor.clearColor()
        let width = 1.0

        let borderLine = UIView(frame: CGRectMake(0, self.frame.height - width, self.frame.width, width))
        borderLine.backgroundColor = borderColor
        self.addSubview(borderLine)
    }
}

и затем добавьте это в ваш viewDidLoad, заменив yourTextField на вашу переменную UITextField и любым цветом, который вы хотите на границе

yourTextField.setBottomBorder(UIColor.blackColor())

Это в основном добавляет вид с этим цветом в нижней части текстового поля.

  • 0
    Отличное решение, работает с четким фоном в отличие от некоторых других.
  • 1
    не забудьте добавить вызов func в viewDidLayoutSubviews () при использовании автоматического макета :) в противном случае ваша строка не будет правильно соответствовать фрейму.
10

Изображение 1891

Цель C

        [txt.layer setBackgroundColor: [[UIColor whiteColor] CGColor]];
        [txt.layer setBorderColor: [[UIColor grayColor] CGColor]];
        [txt.layer setBorderWidth: 0.0];
        [txt.layer setCornerRadius:12.0f];
        [txt.layer setMasksToBounds:NO];
        [txt.layer setShadowRadius:2.0f];
        txt.layer.shadowColor = [[UIColor blackColor] CGColor];
        txt.layer.shadowOffset = CGSizeMake(1.0f, 1.0f);
        txt.layer.shadowOpacity = 1.0f;
        txt.layer.shadowRadius = 1.0f;

Swift

        txt.layer.backgroundColor = UIColor.white.cgColor
        txt.layer.borderColor = UIColor.gray.cgColor
        txt.layer.borderWidth = 0.0
        txt.layer.cornerRadius = 5
        txt.layer.masksToBounds = false
        txt.layer.shadowRadius = 2.0
        txt.layer.shadowColor = UIColor.black.cgColor
        txt.layer.shadowOffset = CGSize.init(width: 1.0, height: 1.0)
        txt.layer.shadowOpacity = 1.0
        txt.layer.shadowRadius = 1.0
6

В Swift 3. Вы можете создать расширение и добавить его после класса просмотра.

extension UITextField
{
    func setBottomBorder(borderColor: UIColor)
    {

        self.borderStyle = UITextBorderStyle.none
        self.backgroundColor = UIColor.clear
        let width = 1.0

        let borderLine = UIView()
        borderLine.frame = CGRect(x: 0, y: Double(self.frame.height) - width, width: Double(self.frame.width), height: width)

        borderLine.backgroundColor = borderColor
        self.addSubview(borderLine)
    }
}
  • 1
    Это работает только для меня, если вы вызываете его в viewDidLayoutSubviews (), а не в viewDidLoad (). Это было намерение здесь?
6

Что я сделал, так это создать расширение для UITextField и добавить редактируемое свойство Designer. Установка этого свойства в любой цвет изменит границу (снизу) на этот цвет (при установке других границ на none).

Так как это также требует изменения цвета текста владельца места, я также добавил это к расширению.

    extension UITextField {

    @IBInspectable var placeHolderColor: UIColor? {
        get {
            return self.placeHolderColor
        }
        set {
            self.attributedPlaceholder = NSAttributedString(string:self.placeholder != nil ? self.placeholder! : "", attributes:[NSForegroundColorAttributeName: newValue!])
        }
    }


    @IBInspectable var bottomBorderColor: UIColor? {
        get {
            return self.bottomBorderColor
        }
        set {
            self.borderStyle = UITextBorderStyle.None;
            let border = CALayer()
            let width = CGFloat(0.5)
            border.borderColor = newValue?.CGColor
            border.frame = CGRect(x: 0, y: self.frame.size.height - width,   width:  self.frame.size.width, height: self.frame.size.height)

            border.borderWidth = width
            self.layer.addSublayer(border)
            self.layer.masksToBounds = true

        }
    }
}
  • 0
    Я думаю, что в Swift 4.0 вам нужно изменить «набор» на «didSet», но в противном случае это работает, спасибо
3

Пожалуйста, посмотрите на приведенный ниже пример кода;

Свифт 4:

@IBDesignable class DesignableUITextField: UITextField {

    let border = CALayer()

    @IBInspectable var borderColor: UIColor? {
        didSet {
            setup()
        }
    }

    @IBInspectable var borderWidth: CGFloat = 0.5 {
        didSet {
            setup()
        }
    }

    func setup() {
        border.borderColor = self.borderColor?.cgColor

        border.borderWidth = borderWidth
        self.layer.addSublayer(border)
        self.layer.masksToBounds = true
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        border.frame = CGRect(x: 0, y: self.frame.size.height - borderWidth, width:  self.frame.size.width, height: self.frame.size.height)
    }
 }
3

Вот код swift3 с @IBInspectable

создать новый файл Cocoa Touch Class Swift File

import UIKit


extension UIView {

@IBInspectable var cornerRadius: CGFloat {
    get {
        return layer.cornerRadius
    }
    set {
        layer.cornerRadius = newValue
        layer.masksToBounds = newValue > 0
    }
}

@IBInspectable var borderWidth: CGFloat {
    get {
        return layer.borderWidth
    }
    set {
        layer.borderWidth = newValue
    }
}

@IBInspectable var borderColor: UIColor? {
    get {
        return UIColor(cgColor: layer.borderColor!)
    }
    set {
        layer.borderColor = newValue?.cgColor
    }
}

@IBInspectable var leftBorderWidth: CGFloat {
    get {
        return 0.0   // Just to satisfy property
    }
    set {
        let line = UIView(frame: CGRect(x: 0.0, y: 0.0, width: newValue, height: bounds.height))
        line.translatesAutoresizingMaskIntoConstraints = false
        line.backgroundColor = UIColor(cgColor: layer.borderColor!)
       line.tag = 110
        self.addSubview(line)

        let views = ["line": line]
        let metrics = ["lineWidth": newValue]
        addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "|[line(==lineWidth)]", options: [], metrics: metrics, views: views))
        addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[line]|", options: [], metrics: nil, views: views))
    }
}

@IBInspectable var topBorderWidth: CGFloat {
    get {
        return 0.0   // Just to satisfy property
    }
    set {
        let line = UIView(frame: CGRect(x: 0.0, y: 0.0, width: bounds.width, height: newValue))
        line.translatesAutoresizingMaskIntoConstraints = false
        line.backgroundColor = borderColor
       line.tag = 110
        self.addSubview(line)

        let views = ["line": line]
        let metrics = ["lineWidth": newValue]
        addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "|[line]|", options: [], metrics: nil, views: views))
        addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[line(==lineWidth)]", options: [], metrics: metrics, views: views))
    }
}

@IBInspectable var rightBorderWidth: CGFloat {
    get {
        return 0.0   // Just to satisfy property
    }
    set {
        let line = UIView(frame: CGRect(x: bounds.width, y: 0.0, width: newValue, height: bounds.height))
        line.translatesAutoresizingMaskIntoConstraints = false
        line.backgroundColor = borderColor
       line.tag = 110
        self.addSubview(line)

        let views = ["line": line]
        let metrics = ["lineWidth": newValue]
        addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "[line(==lineWidth)]|", options: [], metrics: metrics, views: views))
        addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[line]|", options: [], metrics: nil, views: views))
    }
}
@IBInspectable var bottomBorderWidth: CGFloat {
    get {
        return 0.0   // Just to satisfy property
    }
    set {
        let line = UIView(frame: CGRect(x: 0.0, y: bounds.height, width: bounds.width, height: newValue))
        line.translatesAutoresizingMaskIntoConstraints = false
        line.backgroundColor = borderColor
      line.tag = 110
        self.addSubview(line)

        let views = ["line": line]
        let metrics = ["lineWidth": newValue]
        addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "|[line]|", options: [], metrics: nil, views: views))
        addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[line(==lineWidth)]|", options: [], metrics: metrics, views: views))
    }
}
 func removeborder() {
      for view in self.subviews {
           if view.tag == 110  {
                view.removeFromSuperview()
           }

      }
 }

}

и замените файл на приведенный ниже код, и вы получите опцию в инспекторе атрибутов раскадровки, подобном этому

Изображение 1892

Наслаждайтесь:)

1

** Здесь myTF - выход для MT TEXT FIELD **

        let border = CALayer()
        let width = CGFloat(2.0)
        border.borderColor = UIColor.darkGray.cgColor
        border.frame = CGRect(x: 0, y: self.myTF.frame.size.height - width, width:  self.myTF.frame.size.width, height: self.myTF.frame.size.height)

        border.borderWidth = width
        self.myTF.layer.addSublayer(border)
        self.myTF.layer.masksToBounds = true
0

Вы можете использовать этот ОРГАНИЗИРОВАННЫЙ, а также НАСТРОИТЬ следующее расширение:

" Реализация одной строки" в viewDidAppear (так что размер кадра будет правильным):

// Add layer in your textfield    
yourTextField.addLayer(.bottom).addPadding(.left)


// Extension
    extension UITextField {

    enum Position {
        case up, bottom, right, left
    }

    //  MARK: - Add Single Line Layer
    func addLayer(_ position: Position) -> UITextField {

        // bottom layer
        let bottomLayer = CALayer()
        // set width
        let height = CGFloat(1.0)
        bottomLayer.borderWidth = height
        // set color
        bottomLayer.borderColor = UIColor.white.cgColor
        // set frame
        // y position changes according to the position
        let yOrigin = position == .up ? 0.0 : frame.size.height - height
        bottomLayer.frame = CGRect.init(x: 0, y: yOrigin, width: frame.size.width, height: height)
        layer.addSublayer(bottomLayer)
        layer.masksToBounds = true

        return self
    }

    // Add right/left padding view in textfield
    func addPadding(_ position: Position, withImage image: UIImage? = nil) {
        let paddingHeight = frame.size.height
        let paddingViewFrame = CGRect.init(x: 0.0, y: 0.0, width: paddingHeight * 0.6, height: paddingHeight)
        let paddingImageView = UIImageView.init(frame: paddingViewFrame)
        paddingImageView.contentMode = .scaleAspectFit

        if let paddingImage = image {
            paddingImageView.image = paddingImage
        }

        // Add Left/Right view mode
        switch position {
        case .left:
            leftView        = paddingImageView
            leftViewMode    = .always
        case .right:
            rightView       = paddingImageView
            rightViewMode    = .always
        default:
            break
        }
    }
}
0

вы можете создать одно изображение для нижней границы и установить его на фон вашего UITextField:

 yourTextField.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"yourBorderedImageName"]];

или установите borderStyle равным none и поместите изображение строки точно равной длине в текстовое поле!

  • 0
    Я взгляну на этот saurabh. Но будет здорово, если мы сделаем это с помощью кода? У вас есть идеи?
-1
import UIkit 

extension UITextField

{

func underlinedLogin()

{

    let border = CALayer()

    let width = CGFloat(1.0)

    border.borderColor = UIColor.black.cgColor
    border.frame = CGRect(x: 0, y: self.frame.size.height - width, width:  self.frame.size.width, height: self.frame.size.height)
    border.borderWidth = width
    self.layer.addSublayer(border)
    self.layer.masksToBounds = true
}

}

вызов метода на viewdidload

mobileNumberTextField.underlinedLogin()

passwordTextField.underlinedLogin()

//выбираем как текстовое поле на основной плате

Изображение 1893

Ещё вопросы

Сообщество Overcoder
Наверх
Меню