Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

在iOS17上闪烁的光标只在第一个输入的地方 #1

Open
liuyunl opened this issue May 8, 2024 · 2 comments
Open

在iOS17上闪烁的光标只在第一个输入的地方 #1

liuyunl opened this issue May 8, 2024 · 2 comments

Comments

@liuyunl
Copy link

liuyunl commented May 8, 2024

No description provided.

@liuyunl
Copy link
Author

liuyunl commented May 8, 2024

我修改了一下 加了一个layerArray
class JHVerifyCodeView: UIView {

open var inputBlock: ((_ code: String) -> Void)? = nil
open var finishBlock: ((_ codeView: JHVerifyCodeView, _ code: String) -> Void)? = nil

private var config: JHVCConfig! = nil
private var textField: UITextField = UITextField()
private var inputFinish: Bool = false
private var inputFinishIndex: Int = 0
//===============================新加一个layerArray===================================
private var layerArray = [CAShapeLayer]()
//==================================================================================


required public init?(coder: NSCoder) {
    super.init(coder: coder)
}

override init(frame: CGRect) {
    fatalError("Use init(frame:config:) instead")
}

init(frame: CGRect, config: JHVCConfig) {
    super.init(frame: frame)
    
    self.config = config
    setupView(frame)
}

deinit {
    NotificationCenter.default.removeObserver(self)
}

// MARK: --- view layout
func setupView(_ frame: CGRect){
    if frame.size.width <= 0 || frame.size.height <= 0 || config.inputBoxNumber == 0 || config.inputBoxWidth > frame.size.width {
        return
    }
    
    let spacing = config.inputBoxSpacing
    var width: CGFloat = 0.0
    
    if config.inputBoxWidth > 0 {
        width = config.inputBoxWidth
    }
    
    if width > 0 {
        config.leftMargin = (frame.width - width * CGFloat(config.inputBoxNumber) - spacing * CGFloat(config.inputBoxNumber - 1)) * 0.5
    }else{
        let totalSpacing = spacing * CGFloat(config.inputBoxNumber - 1)
        config.inputBoxWidth = (frame.width - totalSpacing - config.leftMargin * 2.0) / CGFloat(config.inputBoxNumber);
        
        width = config.inputBoxWidth
    }
    
    if config.leftMargin < 0 {
        config.leftMargin = 0
        
        let totalSpacing = spacing * CGFloat(config.inputBoxNumber - 1)
        config.inputBoxWidth = (frame.width - totalSpacing - config.leftMargin * 2.0) / CGFloat(config.inputBoxNumber);
        
        width = config.inputBoxWidth
    }
    
    var height: CGFloat = 0.0
    if config.inputBoxHeight > frame.height {
        config.inputBoxHeight = frame.height
    }
    height = config.inputBoxHeight
    
    if config.showUnderLine {
        if config.underLineSize.width <= 0 {
            config.underLineSize.width = width
        }
        
        if config.underLineSize.height <= 0 {
            config.underLineSize.height = 1
        }
    }
    
    //
    for i in 0..<config.inputBoxNumber {
        
        let x = config.leftMargin + (width + spacing) * CGFloat(i)
        let y = (frame.height - height) * 0.5
        
        let textField = UITextField()
        textField.tag = i
        textField.textAlignment = .center
        textField.isUserInteractionEnabled = false
        textField.isSecureTextEntry = config.secureTextEntry
        textField.frame = CGRect(x: x, y: y, width: width, height: height)
        
        if config.inputBoxBorderWidth > 0 {
            textField.layer.borderWidth = config.inputBoxBorderWidth
        }
        
        if config.inputBoxCornerRadius > 0 {
            textField.layer.cornerRadius = config.inputBoxCornerRadius
        }
        
        if config.inputBoxColor != nil {
            textField.layer.borderColor = config.inputBoxColor?.cgColor
        }
        
        if config.tintColor != nil {
            if width > 2 && height > 8 {
                let w: CGFloat = 2
                let y: CGFloat = 4
                let x: CGFloat = (width - w) * 0.5
                let h: CGFloat = height - 2 * y
                
                let path: UIBezierPath = UIBezierPath(rect: CGRect(x: x, y: y, width: w, height: h))
                let layer: CAShapeLayer = CAShapeLayer()
                layer.path = path.cgPath
                layer.fillColor = config.tintColor?.cgColor
                layer.add(alphaAnimation(), forKey: "kFlickerAnimation")
                if i != 0 {
                    layer.isHidden = true
                }
                layerArray.append(layer)
                textField.layer.addSublayer(layer)
            }
        }
        
        if config.font != nil {
            textField.font = config.font
        }
        
        if config.textColor != nil {
            textField.textColor = config.textColor
        }
        
        if config.showUnderLine {
            let x: CGFloat = (width - config.underLineSize.width) * 0.5
            let y: CGFloat = (height - config.underLineSize.height)
            let frame: CGRect = CGRect(x: x, y: y, width: config.underLineSize.width, height: config.underLineSize.height)
            
            let underLine: UIView = UIView()
            underLine.tag = 100
            underLine.frame = frame
            underLine.backgroundColor = config.underLineColor
            textField.addSubview(underLine)
        }
        
        self.addSubview(textField)
    }
    
    //
    self.addGestureRecognizer(UITapGestureRecognizer.init(target: self, action: #selector(tapActioin)))
    
    //
    textField.isHidden = true
    textField.keyboardType = config.keyboardType
    textField.isSecureTextEntry = config.useSystemPasswordKeyboard
    textField.frame = CGRect(x: 0, y: frame.height, width: 0, height: 0)
    if #available(iOS 12.0, *) {
        textField.textContentType = .oneTimeCode
    }
    self.addSubview(textField)
    
    //
    NotificationCenter.default.addObserver(self, selector: #selector(textChange), name: UITextField.textDidChangeNotification, object: textField)
    
    
    //
    if config.autoShowKeyboard {
        let time: TimeInterval = config.autoShowKeyboardDelay
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + time) {
            self.textField.becomeFirstResponder()
        }
    }
}

// MARK: --- event
@objc func tapActioin() {
    textField.becomeFirstResponder()
}

@objc func textChange() {
    //
    setDefault()
    
    //
    let text: NSString = (textField.text?.trimmingCharacters(in: CharacterSet(charactersIn: " ")) ?? "") as NSString
    
    //
    var filterText: NSString = ""
    for i in 0 ..< text.length {
        let c: unichar = text.character(at: i)
        if config.inputType == JHVCConfigInputType.number_alphabet {
            if (c >= 48 && c <= 57) || (c >= 65 && c <= 90) || (c >= 97 && c <= 122) {
                filterText = filterText.appendingFormat("%c", c)
            }
        }else if config.inputType == JHVCConfigInputType.number {
            if (c >= 48 && c <= 57) {
                filterText = filterText.appendingFormat("%c", c)
            }
        }else if config.inputType == JHVCConfigInputType.alphabet {
            if (c >= 65 && c <= 90) || (c >= 97 && c <= 122) {
                filterText = filterText.appendingFormat("%c", c)
            }
        }
    }
    
    //
    let count: Int = config.inputBoxNumber
    if filterText.length > count {
        filterText = filterText.substring(to: count) as NSString
    }
    
    textField.text = filterText as String
    if inputBlock != nil {
        inputBlock!(filterText as String)
    }
    
    //
    setValue(filterText)
    
    //
    flickerAnimation(filterText)
    
    //
    if inputFinish {
        finish()
    }
}

func setDefault() {
    for i in 0..<config.inputBoxNumber {
        let subviews: NSArray = self.subviews as NSArray
        
        let textField = subviews[i] as! UITextField
        textField.text = ""
        
        if config.inputBoxColor != nil {
            textField.layer.borderColor = config.inputBoxColor?.cgColor
        }
        
        if config.showFlickerAnimation && layerArray.count > i {
            let layer = layerArray[i]
            layer.isHidden = true
        }
        
        if config.showUnderLine {
            let underLine: UIView = textField.viewWithTag(100)!
            underLine.backgroundColor = config.underLineColor
        }
    }
}

func flickerAnimation(_ text: NSString) {
    if config.showFlickerAnimation && text.length < layerArray.count {
        let layer = layerArray[text.length]
        layer.isHidden = false
    }
}

func alphaAnimation() -> CABasicAnimation {
    let alpha = CABasicAnimation(keyPath: "opacity")
    alpha.fromValue = NSNumber(1.0)
    alpha.toValue = NSNumber(0.0)
    alpha.duration = Double(1.0)
    alpha.repeatCount = MAXFLOAT
    alpha.isRemovedOnCompletion = false
    alpha.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeOut)
    return alpha
}

func setValue(_ text: NSString) {
    inputFinish = text.length == config.inputBoxNumber
    
    for i in 0..<text.length {
        let c: unichar = text.character(at: i)
        let subviews: NSArray = self.subviews as NSArray
        let textField = subviews[i] as! UITextField
        
        textField.text = String.init(format: "%c", c)
        
        if textField.isSecureTextEntry == false && config.customInputHolder.count > 0 {
            textField.text = config.customInputHolder
        }
        
        // Input Status
        var font: UIFont = config.font ?? UIFont.boldSystemFont(ofSize: 16.0)
        var color: UIColor = config.textColor ?? UIColor.black
        var inputBoxColor: UIColor? = config.inputBoxHighlightedColor
        var underLineColor: UIColor? = config.underLineHighlightedColor
        
        // Finish Status
        if inputFinish {
            if inputFinishIndex < config.finishFonts.count {
                let fonts: NSArray = config.finishFonts as NSArray
                font = fonts[inputFinishIndex] as! UIFont
            }
            if inputFinishIndex < config.finishTextColors.count {
                let colors: NSArray = config.finishTextColors as NSArray
                color = colors[inputFinishIndex] as! UIColor
            }
            if inputFinishIndex < config.inputBoxFinishColors.count {
                let colors: NSArray = config.inputBoxFinishColors as NSArray
                inputBoxColor = colors[inputFinishIndex] as? UIColor
            }
            if inputFinishIndex < config.underLineFinishColors.count {
                let colors: NSArray = config.underLineFinishColors as NSArray
                underLineColor = colors[inputFinishIndex] as? UIColor
            }
        }
        
        textField.font = font
        textField.textColor = color
        
        if inputBoxColor != nil {
            textField.layer.borderColor = inputBoxColor!.cgColor
        }
        
        if config.showUnderLine && underLineColor != nil {
            let underLine: UIView? = textField.viewWithTag(100) ?? nil
            underLine?.backgroundColor = underLineColor
        }
    }
}

func finish() {
    if finishBlock != nil {
        finishBlock!(self, textField.text!)
    }
    
    DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()+0.1) {
        self.textField.resignFirstResponder()
    }
}

}

@xjh093
Copy link
Owner

xjh093 commented May 11, 2024

已经修改了。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants