| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- //
- // LNPopupView.swift
- // Lanu
- //
- // Created by OneeChan on 2025/11/14.
- //
- import Foundation
- import UIKit
- import SnapKit
- enum LNPopupViewHeight {
- case auto
- case percent(CGFloat)
- case height(CGFloat)
- }
- class LNPopupView: UIView {
- let container = UIView()
- var containerHeight: LNPopupViewHeight = .auto
- var touchOutsideToCancel = true
-
- override init(frame: CGRect) {
- super.init(frame: frame)
-
- setupViews()
- }
-
- func showIn(_ targetView: UIView? = nil) {
- if let window = targetView as? UIWindow {
- window.addSubview(self)
- } else if let view = targetView?.viewController?.view {
- view.addSubview(self)
- } else if let window = UIView.appKeyWindow {
- window.addSubview(self)
- } else {
- return
- }
- snp.makeConstraints { make in
- make.directionalEdges.equalToSuperview()
- }
- moveToHiddenPosition()
- layoutIfNeeded()
-
- moveToShowupPosition()
-
- backgroundColor = .clear
- UIView.animate(withDuration: 0.2) {
- self.backgroundColor = .black.withAlphaComponent(0.4)
- self.layoutIfNeeded()
- }
- }
-
- func dismiss() {
- endEditing(true)
- moveToHiddenPosition()
- UIView.animate(withDuration: 0.2) {
- self.backgroundColor = .clear
- self.layoutIfNeeded()
- } completion: { [weak self] _ in
- guard let self else { return }
- self.removeFromSuperview()
- }
- }
-
- required init?(coder: NSCoder) {
- fatalError("init(coder:) has not been implemented")
- }
- }
- extension LNPopupView {
- private func setupViews() {
- let bg = UIView()
- bg.onTap { [weak self] in
- guard let self else { return }
- if touchOutsideToCancel {
- self.dismiss()
- } else {
- endEditing(true)
- }
- }
- insertSubview(bg, at: 0)
- bg.snp.makeConstraints { make in
- make.directionalEdges.equalToSuperview()
- }
-
- container.backgroundColor = .white
- container.layer.cornerRadius = 20
- container.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
- addSubview(container)
-
- let dismissView = UIView()
- container.addSubview(dismissView)
- dismissView.snp.makeConstraints { make in
- make.directionalEdges.equalToSuperview()
- }
- dismissView.onTap { [weak self] in
- guard let self else { return }
- endEditing(true)
- }
-
- LNEventDeliver.addObserver(self)
- }
-
- private func moveToHiddenPosition() {
- container.snp.remakeConstraints { make in
- make.leading.trailing.equalToSuperview()
- make.top.equalTo(self.snp.bottom)
- switch containerHeight {
- case .percent(let percent):
- make.height.equalToSuperview().multipliedBy(percent)
- case .height(let height):
- make.height.equalTo(height)
- case .auto: break
- }
- }
- }
-
- private func moveToShowupPosition() {
- container.snp.remakeConstraints { make in
- make.leading.trailing.bottom.equalToSuperview()
- switch containerHeight {
- case .percent(let percent):
- make.height.equalToSuperview().multipliedBy(percent)
- case .height(let height):
- make.height.equalTo(height)
- case .auto: break
- }
- }
- }
-
- private func onKeyboardShowup(_ keyboardHeight: CGFloat) {
- container.snp.remakeConstraints { make in
- make.leading.trailing.equalToSuperview()
- switch containerHeight {
- case .percent(let percent):
- make.height.equalToSuperview().multipliedBy(percent)
- case .height(let height):
- make.height.equalTo(height)
- case .auto: break
- }
- make.bottom.equalToSuperview().offset(-keyboardHeight)
- }
- }
- }
- extension LNPopupView: LNKeyboardNotify {
- func onKeybaordWillShow(curInput: UIView?, keyboardHeight: CGFloat) {
- guard let curInput, curInput.isDescendant(of: self) == true else { return }
- let view = (curInput as? UITextInput)?.visiableView ?? curInput
- let frame = view.convert(view.bounds, to: self)
- let offset = bounds.height - frame.maxY - keyboardHeight - 16
- if offset < 0 {
- onKeyboardShowup(-offset)
- }
- }
-
- func onKeybaordShow(curInput: UIView?, keyboardHeight: CGFloat) {
- guard curInput?.isDescendant(of: self) == true else { return }
- layoutIfNeeded()
- }
-
- func onKeybaordWillHide(curInput: UIView?) {
- guard curInput?.isDescendant(of: self) == true else { return }
- moveToShowupPosition()
- }
-
- func onKeybaordHide(curInput: UIView?) {
- guard curInput?.isDescendant(of: self) == true else { return }
- layoutIfNeeded()
- }
- }
|