一:简介
在有支付相关的APP中,都有对应的钱包,虽然现在的支付宝,微信支付很流行,但是都是需要绑定自己的银行卡,那么这个银行卡的卡包页面该怎么实现呢?在网上找了许久也没有找到合适的,那就索性自己造轮子。
为了实现相应的功能,仿照支付宝的银行卡卡包开发出相应的页面,页面长这个样子:
二:说明目录
三:具体实现
1. 创建钱包视图容器WalletView
创建继承UIView的WalletView视图, 通过调用contentInset方法来控制top、left、bottom、right四个方向的边距,代码如下:
public var contentInset: UIEdgeInsets {
set {
scrollView.contentInset = newValue
calculateLayoutValues()
}
get {
return scrollView.contentInset
}
}
创建walletHeader方法,用来加载钱包的头部视图,代码如下:
@IBOutlet public weak var walletHeader: UIView? {
willSet {
if let walletHeader = newValue {
scrollView.addSubview(walletHeader)
}
}
didSet {
oldValue?.removeFromSuperview()
calculateLayoutValues()
}
}
2. 初始化WalletView并加载钱包头部视图walletHeader
在需要加载钱包的地方初始化WalletView,并自定义头部视图walletHeader和卡片视图,Demo 中以ViewController页面为例,代码如下:
walletView = WalletView(frame: CGRect(x: 10, y: 0, width: screenw - 20, height: screenh - 20))
self.view.addSubview(walletView)
walletView.walletHeader = walletHeaderView
walletView.useHeaderDistanceForStackedCards = true
walletView.contentInset = UIEdgeInsets(top: 20, left: 0, bottom: 0, right: 0)
3. 在钱包视图中重新加载卡片视图
在钱包视图中重新加载卡片视图,在这里为了灵活修改方便使用,页面布局可以自定义,Demo中模仿支付宝页面进行设计,在CardView视图中,主要实现页面的交互等功能,具体的UI实现在ColoredCardView中实现并继承于CardView,下面会详细说明,重新加载卡片视图方法源码如下:
open func reload(cardViews: [CardView]) {
insert(cardViews: cardViews)
calculateLayoutValues()
}
func insert(cardViews: [CardView]) {
self.insertedCardViews = cardViews
if insertedCardViews.count == 1 {
presentedCardView = insertedCardViews.first
}
}
public var insertedCardViews = [CardView]() {
didSet {
calculateLayoutValues(shouldLayoutWalletView: false)
}
}
在ViewController中调用reload方法代码如下:
walletView.reload(cardViews: coloredCardViews)
4. 在钱包视图中实现添加卡片方法
在展示页面中我们可以看到,在页面的左上角有一个添加按钮,这个按钮的UI布局在头部视图中实现,具体的功能是,添加一个卡片,具体的实现方法如下:
open func insert(cardView: CardView, animated: Bool = false, presented: Bool = false, completion: InsertionCompletion? = nil) {
presentedCardView = presented ? cardView : self.presentedCardView
if animated {
let y = scrollView.convert(CGPoint(x: 0, y: frame.maxY), from: self).y
cardView.frame = CGRect(x: 0, y: y, width: frame.width, height: cardViewHeight)
cardView.layoutIfNeeded()
scrollView.insertSubview(cardView, at: 0)
UIView.animateKeyframes(withDuration: WalletView.insertionAnimationSpeed, delay: 0, options: [.beginFromCurrentState, .calculationModeCubic], animations: { [weak self] in
UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 1.0, animations: {
self?.insert(cardViews: [cardView] + (self?.insertedCardViews ?? []))
self?.layoutWalletView(placeVisibleCardViews: false)
})
}, completion: { [weak self] (_) in
self?.reload(cardViews: self?.insertedCardViews ?? [])
completion?()
})
} else {
reload(cardViews: [cardView] + insertedCardViews)
placeVisibleCardViews()
completion?()
}
}
在ViewController中按钮的触发事件addCardButtonClick方法中调用insert方法代码如下:
@objc func addCardButtonClick(addCardButton:UIButton) {
walletView.insert(cardView: ColoredCardView(), animated: true, presented: true)
}
5. 在钱包视图中实现卡片展示和隐藏回调方法
在钱包视图中实现卡片展示和隐藏回调方法,在展示状态下,需要隐藏掉添加卡片按钮,禁止继续添加卡片,并且显示卡片详细设置内容和删除按钮。在隐藏状态下,需要恢复添加卡片按钮,并且隐藏卡片详细设置内容和删除按钮,核心源码如下:
public var didPresentCardViewBlock: PresentedCardViewDidUpdateBlock?
public var presentedCardView: CardView? {
didSet {
oldValue?.presented = false
presentedCardView?.presented = true
didPresentCardViewBlock?(presentedCardView)
}
}
在ViewController中实现回调功能,代码如下:
walletView.didPresentCardViewBlock = { [weak self] (_) in
self?.showAddCardViewButtonIfNeeded()
}
6. 创建卡片视图ColoredCardView继承于CardView
创建卡片视图ColoredCardView继承于CardView,这个视图主要实现UI界面以及加载内容,定义界面属性代码如下:
class ColoredCardView: CardView, UITableViewDataSource, UITableViewDelegate {
// 银行logo
@objc var cardLogo: UIImageView!
// 开户行名称
@objc var cardName: UILabel!
// 卡片类型
@objc var cardAddress: UILabel!
// 银行卡号
@objc var cardNumber: UILabel!
// 设置列表
@objc var cardTableView: UITableView!
// 卡片视图
@objc var bankCardView: UIView!
// 删除按钮
@objc var removeCardViewButton: UIButton!
override init(frame: CGRect) {
super.init(frame: frame)
setupSubViews()
}
}
7. 在CardView中实现点击手势展示隐藏卡片
在Demo中实现在CardView中点击除了删除按钮外任何位置,都可以触发隐藏卡片的功能,这里是在CardView中添加了手势来实现该功能,代码如下:
public let tapGestureRecognizer = UITapGestureRecognizer()
public let panGestureRecognizer = UIPanGestureRecognizer()
public let longGestureRecognizer = UILongPressGestureRecognizer()
// MARK: Private methods
func setupGestures() {
tapGestureRecognizer.addTarget(self, action: #selector(CardView.tapped))
tapGestureRecognizer.delegate = self
addGestureRecognizer(tapGestureRecognizer)
panGestureRecognizer.addTarget(self, action: #selector(CardView.panned(gestureRecognizer:)))
panGestureRecognizer.delegate = self
addGestureRecognizer(panGestureRecognizer)
longGestureRecognizer.addTarget(self, action: #selector(CardView.longPressed(gestureRecognizer:)))
longGestureRecognizer.delegate = self
addGestureRecognizer(longGestureRecognizer)
}
8. 导入项目使用介绍
最后介绍一下该如何在项目中导入该功能,下载Demo,将Demo中的FBYBankCard.framework文件和ColoredCardView.swift文件导入项目中,在需要加载的页面中直接引用即可:
import FBYBankCard
class ViewController: UIViewController {
@objc var walletView: WalletView!
override func viewDidLoad() {
super.viewDidLoad()
}
}