402 lines
13 KiB
Swift
402 lines
13 KiB
Swift
//
|
||
// LoginView.swift
|
||
// QuickLocation
|
||
//
|
||
// Created by 八条 on 2026/5/26.
|
||
//
|
||
|
||
import UIKit
|
||
import RxSwift
|
||
import RxCocoa
|
||
#if !targetEnvironment(simulator)
|
||
import GeYanSdk
|
||
#endif
|
||
|
||
class LoginView: UIView {
|
||
|
||
var disposeBag = DisposeBag()
|
||
var oneTapLogin = true
|
||
|
||
private func setupRx() {
|
||
backBtn.rx.tap.subscribe(onNext: { _ in
|
||
AppRouter.shared.popOrDismiss()
|
||
}).disposed(by: disposeBag)
|
||
|
||
phoneInputTF.rx.text
|
||
.map { text -> String? in
|
||
guard let text = text else { return nil }
|
||
return String(text.prefix(11))
|
||
}.bind(to: phoneInputTF.rx.text)
|
||
.disposed(by: disposeBag)
|
||
|
||
phoneInputTF.rx.text.orEmpty.map { phone -> Bool in
|
||
if phone.count == 11 {
|
||
return true
|
||
} else {
|
||
return false
|
||
}
|
||
}
|
||
.bind(to: smsCodeBtn.rx.isEnabled)
|
||
.disposed(by: disposeBag)
|
||
}
|
||
|
||
func setupAgreementTextWithCarrier(carrier: String) {
|
||
let text = carrier.isEmpty ? "登录即同意《隐私政策》和《用户协议》" : "登录即同意\(carrier)、《隐私政策》和《用户协议》"
|
||
agreementLabel.text = text
|
||
// 创建段落样式
|
||
let paragraphStyle = NSMutableParagraphStyle()
|
||
// 设置行距(lineSpacing 是行间距,lineHeightMultiple 是行高倍数)
|
||
paragraphStyle.lineSpacing = 4.0 // 行间距
|
||
|
||
let attributedString = NSMutableAttributedString(string: text)
|
||
attributedString.addAttributes([.foregroundColor: UIColor(hexStr: "#A4A7AE"),
|
||
.paragraphStyle: paragraphStyle], range: NSRange(location: 0, length: text.length))
|
||
attributedString.addAttributes([.foregroundColor: UIColor(hexStr: "#16B3FF"),
|
||
.link: "Carrier"],
|
||
range: (text as NSString).range(of: carrier))
|
||
attributedString.addAttributes([.foregroundColor: UIColor(hexStr: "#16B3FF"),
|
||
.link: "UserAgreement"],
|
||
range: (text as NSString).range(of: "《用户协议》"))
|
||
attributedString.addAttributes([.foregroundColor: UIColor(hexStr: "#16B3FF"),
|
||
.link: "PrivacyPolicy"],
|
||
range: (text as NSString).range(of: "《隐私政策》"))
|
||
|
||
agreementTV.attributedText = attributedString
|
||
}
|
||
|
||
private func setupUI() {
|
||
addSubview(bgMaskImage)
|
||
addSubview(backBtn)
|
||
addSubview(guestLoginButton)
|
||
addSubview(welcomeLabel)
|
||
addSubview(phoneNumberLabel)
|
||
addSubview(carrierLabel)
|
||
addSubview(otherPhoneView)
|
||
otherPhoneView.addSubview(phoneInputView)
|
||
otherPhoneView.addSubview(smsCodeInputView)
|
||
addSubview(loginButton)
|
||
addSubview(appleLoginBtn)
|
||
addSubview(wechatLoginBtn)
|
||
addSubview(phoneLoginBtn)
|
||
|
||
addSubview(agreementView)
|
||
agreementView.addSubview(checkBox)
|
||
agreementView.addSubview(agreementTV)
|
||
agreementView.addSubview(agreementLabel)
|
||
|
||
bgMaskImage.layoutChain.edges()
|
||
|
||
backBtn.layoutChain
|
||
.top(54)
|
||
.left(15)
|
||
.width(24)
|
||
.height(24)
|
||
|
||
guestLoginButton.layoutChain
|
||
.centerY(backBtn)
|
||
.right(15)
|
||
.width(85)
|
||
.height(29)
|
||
|
||
welcomeLabel.layoutChain
|
||
.top(202 - kNaviHeight)
|
||
.centerX()
|
||
.edgesHorzontal()
|
||
|
||
phoneNumberLabel.layoutChain
|
||
.topToBottomOfView(welcomeLabel, offset: 78)
|
||
.centerX()
|
||
|
||
carrierLabel.layoutChain
|
||
.topToBottomOfView(phoneNumberLabel, offset: 4)
|
||
.centerX()
|
||
|
||
otherPhoneView.layoutChain
|
||
.topToBottomOfView(welcomeLabel, offset: 43)
|
||
.centerX()
|
||
|
||
phoneInputView.layoutChain
|
||
.edges(excludingEdge: .bottom)
|
||
.width(259)
|
||
.height(50)
|
||
|
||
phoneLineView.layoutChain
|
||
.left(58)
|
||
.centerY()
|
||
.width(1)
|
||
.height(25)
|
||
|
||
areaCodeLab.layoutChain
|
||
.left()
|
||
.rightToView(phoneLineView)
|
||
.centerY()
|
||
|
||
phoneInputTF.layoutChain
|
||
.leftToView(phoneLineView, offset: 13)
|
||
.right()
|
||
.edgesVertical()
|
||
|
||
smsCodeInputView.layoutChain
|
||
.topToBottomOfView(phoneInputView, offset: 20)
|
||
.edges(excludingEdge: .top)
|
||
.widthToView(phoneInputView)
|
||
.heightToView(phoneInputView)
|
||
|
||
smsCodeBtn.layoutChain
|
||
.edgesVertical()
|
||
.right()
|
||
.width(100)
|
||
|
||
smsCodeTF.layoutChain
|
||
.edgesVertical()
|
||
.left(20)
|
||
.rightToLeftOfView(smsCodeBtn)
|
||
|
||
loginButton.layoutChain
|
||
.topToBottomOfView(otherPhoneView, offset: 63)
|
||
.centerX()
|
||
.width(247)
|
||
.height(50)
|
||
|
||
agreementView.layoutChain
|
||
.leftToView(loginButton)
|
||
.rightToView(loginButton)
|
||
.bottom(55)
|
||
.height(30)
|
||
|
||
agreementLabel.layoutChain.edges()
|
||
|
||
checkBox.layoutChain
|
||
.left()
|
||
.centerY()
|
||
.width(12)
|
||
.height(12)
|
||
|
||
agreementTV.layoutChain
|
||
.leftToRightOfView(checkBox, offset: 0)
|
||
.right()
|
||
.top()
|
||
|
||
phoneLoginBtn.layoutChain
|
||
.bottomToTopOfView(agreementView, offset: -81)
|
||
.centerX()
|
||
.width(38)
|
||
.heightToWidth(1)
|
||
|
||
appleLoginBtn.layoutChain
|
||
.rightToLeftOfView(phoneLoginBtn, offset: -43)
|
||
.centerY(phoneLoginBtn)
|
||
.widthToView(phoneLoginBtn)
|
||
.heightToView(phoneLoginBtn)
|
||
|
||
wechatLoginBtn.layoutChain
|
||
.leftToRightOfView(phoneLoginBtn, offset: 43)
|
||
.centerY(phoneLoginBtn)
|
||
.widthToView(phoneLoginBtn)
|
||
.heightToView(phoneLoginBtn)
|
||
}
|
||
|
||
override init(frame: CGRect) {
|
||
super.init(frame: .zero)
|
||
backgroundColor = .white
|
||
setupUI()
|
||
setupRx()
|
||
setupAgreementTextWithCarrier(carrier: "")
|
||
}
|
||
|
||
required init?(coder aDecoder: NSCoder) {
|
||
fatalError("init(coder:) has not been implemented")
|
||
}
|
||
|
||
// MARK: - UI Components
|
||
lazy var bgMaskImage: UIImageView = {
|
||
let iv = UIImageView()
|
||
iv.image = UIImage(named: "Login/bg")
|
||
iv.contentMode = .scaleAspectFill
|
||
return iv
|
||
}()
|
||
|
||
lazy var backBtn: UIButton = {
|
||
let btn = UIButton(type: .custom)
|
||
btn.setImage(UIImage(named: "Common/back"), for: .normal)
|
||
btn.extendEdgeInsets = UIEdgeInsets(top: 54, left: 15, bottom: 50, right: 50)
|
||
return btn
|
||
}()
|
||
|
||
lazy var guestLoginButton: UIButton = {
|
||
let btn = UIButton(type: .system)
|
||
btn.setTitle("游客登录", for: .normal)
|
||
btn.setTitleColor(.white, for: .normal)
|
||
btn.titleLabel?.font = .systemFont(ofSize: 14, weight: .medium)
|
||
btn.setBackgroundImage(UIImage(named: "Login/visitor_bg"), for: .normal)
|
||
return btn
|
||
}()
|
||
|
||
lazy var welcomeLabel: UILabel = {
|
||
let label = UILabel()
|
||
label.text = "欢迎登录"
|
||
label.font = UIFont(name: "DOUYU Font", size: 24)
|
||
label.textColor = UIColor(hexStr: "#030303")
|
||
label.textAlignment = .center
|
||
return label
|
||
}()
|
||
|
||
lazy var phoneNumberLabel: UILabel = {
|
||
let label = UILabel()
|
||
label.font = .systemFont(ofSize: 20, weight: .medium)
|
||
label.textColor = ThemeManager.shared.color.titleAuxColor
|
||
label.textAlignment = .center
|
||
return label
|
||
}()
|
||
|
||
lazy var carrierLabel: UILabel = {
|
||
let label = UILabel()
|
||
label.font = .systemFont(ofSize: 12)
|
||
label.textColor = ThemeManager.shared.color.contentColor
|
||
label.textAlignment = .center
|
||
return label
|
||
}()
|
||
|
||
// 其他手机号登录
|
||
lazy var otherPhoneView: UIView = {
|
||
let view = UIView()
|
||
view.backgroundColor = .clear
|
||
// view.isHidden = true
|
||
return view
|
||
}()
|
||
|
||
// 手机号
|
||
lazy var phoneInputView: UIView = {
|
||
let view = UIView()
|
||
view.backgroundColor = .clear
|
||
view.borderWidth = 1
|
||
view.borderColor = .white
|
||
view.cornerRadius = 8
|
||
view.addSubview(areaCodeLab)
|
||
view.addSubview(phoneLineView)
|
||
view.addSubview(phoneInputTF)
|
||
return view
|
||
}()
|
||
|
||
lazy var areaCodeLab: UILabel = {
|
||
let label = UILabel()
|
||
label.text = "+86"
|
||
label.font = .systemFont(ofSize: 16, weight: .medium)
|
||
label.textColor = .white
|
||
label.textAlignment = .center
|
||
return label
|
||
}()
|
||
|
||
lazy var phoneLineView: UIView = {
|
||
let view = UIView()
|
||
view.backgroundColor = .white
|
||
return view
|
||
}()
|
||
|
||
lazy var phoneInputTF: UITextField = {
|
||
let textField = UITextField()
|
||
textField.font = .systemFont(ofSize: 16, weight: .medium)
|
||
textField.placeholderColor(placeholder: "请输入手机号码",
|
||
color: .white)
|
||
// textField.tintColor = ThemeManager.shared.color.mainColor
|
||
textField.clearButtonMode = .whileEditing
|
||
textField.keyboardType = .numberPad
|
||
return textField
|
||
}()
|
||
|
||
// 验证码
|
||
lazy var smsCodeInputView: UIView = {
|
||
let view = UIView()
|
||
view.backgroundColor = .clear
|
||
view.borderWidth = 1
|
||
view.borderColor = .white
|
||
view.cornerRadius = 8
|
||
view.addSubview(smsCodeTF)
|
||
view.addSubview(smsCodeBtn)
|
||
return view
|
||
}()
|
||
|
||
lazy var smsCodeTF: UITextField = {
|
||
let textField = UITextField()
|
||
textField.font = .systemFont(ofSize: 16, weight: .medium)
|
||
textField.placeholderColor(placeholder: "请输入验证码",
|
||
color: .white)
|
||
textField.keyboardType = .numbersAndPunctuation
|
||
return textField
|
||
}()
|
||
|
||
lazy var smsCodeBtn: UIButton = {
|
||
let button = UIButton()
|
||
button.setTitle("获取验证码", for: .normal)
|
||
button.setTitleColor(UIColor(hexStr: "#030303"), for: .normal)
|
||
button.setTitleColor(UIColor(hexStr: "#999999", alpha: 1.0), for: .disabled)
|
||
button.titleLabel?.font = .systemFont(ofSize: 16, weight: .medium)
|
||
return button
|
||
}()
|
||
|
||
lazy var loginButton: UIButton = {
|
||
let btn = UIButton(type: .system)
|
||
btn.setTitle("立即登录", for: .normal)
|
||
btn.setTitleColor(UIColor(hexStr: "#0F2846"), for: .normal)
|
||
btn.titleLabel?.font = .systemFont(ofSize: 16, weight: .medium)
|
||
btn.setBackgroundImage(UIImage(named: "Login/login_bg"), for: .normal)
|
||
return btn
|
||
}()
|
||
|
||
lazy var wechatLoginBtn: UIButton = {
|
||
let btn = UIButton(type: .custom)
|
||
btn.setBackgroundImage(UIImage(named: "Login/wechat"), for: .normal)
|
||
btn.backgroundColor = .clear
|
||
return btn
|
||
}()
|
||
|
||
lazy var appleLoginBtn: UIButton = {
|
||
let btn = UIButton(type: .custom)
|
||
btn.setBackgroundImage(UIImage(named: "Login/apple"), for: .normal)
|
||
btn.backgroundColor = .clear
|
||
return btn
|
||
}()
|
||
|
||
lazy var phoneLoginBtn: UIButton = {
|
||
let btn = UIButton(type: .custom)
|
||
btn.setBackgroundImage(UIImage(named: "Login/phone"), for: .normal)
|
||
btn.backgroundColor = .clear
|
||
return btn
|
||
}()
|
||
|
||
lazy var agreementView: UIView = {
|
||
let view = UIView()
|
||
view.backgroundColor = .clear
|
||
return view
|
||
}()
|
||
|
||
lazy var checkBox: UIButton = {
|
||
let btn = UIButton(type: .custom)
|
||
btn.setImage(UIImage(named: "Login/checkbox"), for: .normal)
|
||
btn.setImage(UIImage(named: "Login/selected"), for: .selected)
|
||
btn.extendEdgeInsets = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20)
|
||
return btn
|
||
}()
|
||
|
||
lazy var agreementLabel: UILabel = {
|
||
let label = UILabel()
|
||
label.textColor = .clear
|
||
label.numberOfLines = 1
|
||
label.textAlignment = .center
|
||
label.font = .systemFont(ofSize: 10)
|
||
return label
|
||
}()
|
||
|
||
lazy var agreementTV: UITextView = {
|
||
let textView = UITextView()
|
||
textView.font = .systemFont(ofSize: 10, weight: .medium)
|
||
textView.backgroundColor = .clear
|
||
textView.isEditable = false
|
||
textView.isScrollEnabled = false
|
||
textView.isSelectable = false
|
||
textView.linkTextAttributes = [:]
|
||
|
||
return textView
|
||
}()
|
||
}
|