// // PaymentSetAmountDialogView.swift // suixinkan // import SnapKit import UIKit /// 设置收款金额弹窗,对齐 Android `SetAmountDialog`。 final class PaymentSetAmountDialogView: KeyboardAvoidingDialogView { var onConfirm: (() -> Void)? var onCancel: (() -> Void)? var onAmountChange: ((String) -> Void)? var onRemarkChange: ((String) -> Void)? private let dimView = UIView() private let cardView = UIView() private let titleLabel = UILabel() private let amountContainer = UIView() private let currencyLabel = UILabel() private let amountField = UITextField() private let remarkTitleLabel = UILabel() private let remarkField = UITextView() private let remarkCountLabel = UILabel() private let buttonStack = UIStackView() private let cancelButton = UIButton(type: .system) private let confirmButton = UIButton(type: .system) override init(frame: CGRect) { super.init(frame: frame) setupUI() } @available(*, unavailable) required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func apply(amount: String, remark: String) { if amountField.text != amount { amountField.text = amount } if remarkField.text != remark { remarkField.text = remark } remarkCountLabel.text = "\(remark.count)/200" } func show(in parent: UIView) { frame = parent.bounds autoresizingMask = [.flexibleWidth, .flexibleHeight] alpha = 0 parent.addSubview(self) layoutIfNeeded() amountField.becomeFirstResponder() UIView.animate(withDuration: 0.2) { self.alpha = 1 } } func dismiss() { endEditing(true) UIView.animate(withDuration: 0.2, animations: { self.alpha = 0 }, completion: { _ in self.removeFromSuperview() }) } private func setupUI() { keyboardAvoidingContentView = cardView dimView.backgroundColor = AppColor.overlayScrim dimView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(cancelTapped))) cardView.backgroundColor = .white cardView.layer.cornerRadius = AppRadius.xl cardView.clipsToBounds = true titleLabel.text = "收款金额" titleLabel.font = .systemFont(ofSize: 18, weight: .bold) titleLabel.textColor = AppColor.textPrimary amountContainer.backgroundColor = AppColor.inputBackground amountContainer.layer.cornerRadius = AppRadius.sm currencyLabel.text = "¥" currencyLabel.font = .systemFont(ofSize: 20, weight: .bold) currencyLabel.textColor = AppColor.textPrimary amountField.placeholder = "请输入收款金额" amountField.font = .systemFont(ofSize: 18, weight: .medium) amountField.keyboardType = .decimalPad amountField.borderStyle = .none amountField.backgroundColor = .clear amountField.addTarget(self, action: #selector(amountChanged), for: .editingChanged) remarkTitleLabel.text = "备注 (选填)" remarkTitleLabel.font = .systemFont(ofSize: 14) remarkTitleLabel.textColor = UIColor(hex: 0x4B5563) remarkField.font = .systemFont(ofSize: 14) remarkField.textColor = AppColor.textPrimary remarkField.backgroundColor = .white remarkField.layer.borderColor = UIColor(hex: 0xE5E7EB).cgColor remarkField.layer.borderWidth = 1 remarkField.layer.cornerRadius = AppRadius.sm remarkField.textContainerInset = UIEdgeInsets(top: 10, left: 8, bottom: 10, right: 8) remarkField.delegate = self remarkCountLabel.font = .systemFont(ofSize: 12) remarkCountLabel.textColor = AppColor.textTertiary remarkCountLabel.textAlignment = .right remarkCountLabel.text = "0/200" buttonStack.axis = .horizontal buttonStack.spacing = AppSpacing.sm buttonStack.distribution = .fillEqually cancelButton.setTitle("取消", for: .normal) cancelButton.setTitleColor(AppColor.textSecondary, for: .normal) cancelButton.titleLabel?.font = .systemFont(ofSize: 16, weight: .medium) cancelButton.backgroundColor = AppColor.inputBackground cancelButton.layer.cornerRadius = AppRadius.sm cancelButton.addTarget(self, action: #selector(cancelTapped), for: .touchUpInside) confirmButton.setTitle("确定", for: .normal) confirmButton.setTitleColor(.white, for: .normal) confirmButton.titleLabel?.font = .systemFont(ofSize: 16, weight: .medium) confirmButton.backgroundColor = AppColor.primary confirmButton.layer.cornerRadius = AppRadius.sm confirmButton.addTarget(self, action: #selector(confirmTapped), for: .touchUpInside) addSubview(dimView) addSubview(cardView) cardView.addSubview(titleLabel) cardView.addSubview(amountContainer) amountContainer.addSubview(currencyLabel) amountContainer.addSubview(amountField) cardView.addSubview(remarkTitleLabel) cardView.addSubview(remarkField) cardView.addSubview(remarkCountLabel) cardView.addSubview(buttonStack) buttonStack.addArrangedSubview(cancelButton) buttonStack.addArrangedSubview(confirmButton) dimView.snp.makeConstraints { make in make.edges.equalToSuperview() } cardView.snp.makeConstraints { make in make.leading.trailing.equalToSuperview().inset(AppSpacing.md) keyboardAvoidingCenterYConstraint = make.centerY.equalToSuperview().constraint } titleLabel.snp.makeConstraints { make in make.top.leading.trailing.equalToSuperview().inset(AppSpacing.md) } amountContainer.snp.makeConstraints { make in make.top.equalTo(titleLabel.snp.bottom).offset(20) make.leading.trailing.equalToSuperview().inset(AppSpacing.md) make.height.equalTo(48) } currencyLabel.snp.makeConstraints { make in make.leading.equalToSuperview().offset(AppSpacing.sm) make.centerY.equalToSuperview() } amountField.snp.makeConstraints { make in make.leading.equalTo(currencyLabel.snp.trailing).offset(AppSpacing.xs) make.trailing.equalToSuperview().inset(AppSpacing.sm) make.centerY.equalToSuperview() } remarkTitleLabel.snp.makeConstraints { make in make.top.equalTo(amountContainer.snp.bottom).offset(AppSpacing.md) make.leading.trailing.equalToSuperview().inset(AppSpacing.md) } remarkField.snp.makeConstraints { make in make.top.equalTo(remarkTitleLabel.snp.bottom).offset(AppSpacing.xs) make.leading.trailing.equalToSuperview().inset(AppSpacing.md) make.height.equalTo(100) } remarkCountLabel.snp.makeConstraints { make in make.top.equalTo(remarkField.snp.bottom).offset(AppSpacing.xxs) make.trailing.equalToSuperview().inset(AppSpacing.md) } buttonStack.snp.makeConstraints { make in make.top.equalTo(remarkCountLabel.snp.bottom).offset(AppSpacing.lg) make.leading.trailing.bottom.equalToSuperview().inset(AppSpacing.md) make.height.equalTo(44) } } @objc private func amountChanged() { onAmountChange?(amountField.text ?? "") } @objc private func cancelTapped() { onCancel?() } @objc private func confirmTapped() { onConfirm?() } } extension PaymentSetAmountDialogView: UITextViewDelegate { func textViewDidChange(_ textView: UITextView) { onRemarkChange?(textView.text ?? "") } }