【发布时间】:2021-01-20 04:45:10
【问题描述】:
我知道以前有人问过这个问题,但在我的情况下无法弄清楚如何以最短的方式实现这一点。
当我点击“添加”按钮(参见下面的 GIF)时,动画功能会为“imageView”(在本例中为银河图像)设置动画以飞到购物车,即“notificationButton”。此外,“添加”按钮更改为“删除”,按钮颜色从黑色变为红色(参见下面的 GIF)。没关系。
现在,当我第二次单击按钮时,即取消选择它,即使其变为默认状态,一切都会反转,但图像仍然会飞到购物车!
现在,当我第二次将按钮按回其默认位置时,我想将动画飞行 imageView 动画反转到其原始位置,如果再次按我想要的次数再次按下按钮,则再次返回原始飞行动画。
虽然我在这里添加了完整的 ProductViewController 代码,但是你跳过所有内容并查看最后一个扩展 ProductViewController
我知道这很可能有两个步骤 -
i) 识别第二次按下“buttonHandlerAddToCart”按钮,即从选定/被选定步骤到默认步骤。
ii) 在 ProductViewController 中反转动画函数“func animation”。
怎么办?
相关代码:
SSBadgeButton:-
导入 UIKit
class SSBadgeButton: UIButton {
var badgeLabel = UILabel()
var badge: String? {
didSet {
addBadgeToButon(badge: badge)
}
}
public var badgeBackgroundColor = UIColor.red {
didSet {
badgeLabel.backgroundColor = badgeBackgroundColor
}
}
public var badgeTextColor = UIColor.white {
didSet {
badgeLabel.textColor = badgeTextColor
}
}
public var badgeFont = UIFont.systemFont(ofSize: 12.0) {
didSet {
badgeLabel.font = badgeFont
}
}
public var badgeEdgeInsets: UIEdgeInsets? {
didSet {
addBadgeToButon(badge: badge)
}
}
override init(frame: CGRect) {
super.init(frame: frame)
addBadgeToButon(badge: nil)
}
func addBadgeToButon(badge: String?) {
badgeLabel.text = badge
badgeLabel.textColor = badgeTextColor
badgeLabel.backgroundColor = badgeBackgroundColor
badgeLabel.font = badgeFont
badgeLabel.sizeToFit()
badgeLabel.textAlignment = .center
let badgeSize = badgeLabel.frame.size
let height = max(18, Double(badgeSize.height) + 5.0)
let width = max(height, Double(badgeSize.width) + 10.0)
var vertical: Double?, horizontal: Double?
if let badgeInset = self.badgeEdgeInsets {
vertical = Double(badgeInset.top) - Double(badgeInset.bottom)
horizontal = Double(badgeInset.left) - Double(badgeInset.right)
let x = (Double(bounds.size.width) - 10 + horizontal!)
let y = -(Double(badgeSize.height) / 2) - 10 + vertical!
badgeLabel.frame = CGRect(x: x, y: y, width: width, height: height)
} else {
let x = self.frame.width - CGFloat((width / 2.0))
let y = CGFloat(-(height / 2.0))
badgeLabel.frame = CGRect(x: x, y: y, width: CGFloat(width), height: CGFloat(height))
}
badgeLabel.layer.cornerRadius = badgeLabel.frame.height/2
badgeLabel.layer.masksToBounds = true
addSubview(badgeLabel)
badgeLabel.isHidden = badge != nil ? false : true
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.addBadgeToButon(badge: nil)
fatalError("init(coder:) has not been implemented")
}
}
ProductViewController 代码:
import UIKit
class ProductViewController: UIViewController, UITableViewDataSource,
UITableViewDelegate {
let notificationButton = SSBadgeButton()
let rightbarbuttonimage = UIImage(named:"ic_cart")
fileprivate var cart = Cart()
let scrollView = UIScrollView()
let sections = ["Section A", "Section B","Section C", "Section D","Section E","Section F","Section G","Section H", "Section I","Section J","Section K","Section L"]
let rowspersection = [2,3,1,2,2,3,3,1,4,2,1,2]
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
self.tableView.backgroundColor = UIColor.gray
//Add and setup scroll view
self.tableView.addSubview(self.scrollView)
self.scrollView.translatesAutoresizingMaskIntoConstraints = false;
//Constrain scroll view
self.scrollView.leadingAnchor.constraint(equalTo: self.tableView.leadingAnchor, constant: 20).isActive = true;
self.scrollView.topAnchor.constraint(equalTo: self.tableView.topAnchor, constant: 20).isActive = true;
self.scrollView.trailingAnchor.constraint(equalTo: self.tableView.trailingAnchor, constant: -20).isActive = true;
self.scrollView.bottomAnchor.constraint(equalTo: self.tableView.bottomAnchor, constant: -20).isActive = true;
// customising rightBarButtonItems as notificationbutton
notificationButton.frame = CGRect(x: 0, y: 0, width: 44, height: 44)
notificationButton.setImage(UIImage(named: "ic_cart")?.withRenderingMode(.alwaysTemplate), for: .normal)
notificationButton.badgeEdgeInsets = UIEdgeInsets(top: 20, left: 0, bottom: 0, right: 15)
self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: notificationButton)
//following register is needed because I have rightbarbuttonitem customised as uibutton i.e. notificationbutton
notificationButton.addTarget(self, action: #selector(self.registerTapped(_:)), for: .touchUpInside)
}
@objc func registerTapped(_ sender: UIButton) {
self.performSegue(withIdentifier: "showCart", sender: nil)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
//Workaround to avoid the fadout the right bar button item
self.navigationItem.rightBarButtonItem?.isEnabled = false
self.navigationItem.rightBarButtonItem?.isEnabled = true
//Update cart if some items quantity is equal to 0 and reload the product table and right button bar item
cart.updateCart()
//self.navigationItem.rightBarButtonItem?.title = "Checkout (\(cart.items.count))"
notificationButton.badge = String(cart.items.count)// making badge equal to no.ofitems in cart
tableView.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// this segue to transfer data
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showCart" {
if let cartViewController = segue.destination as? CartViewController {
cartViewController.cart = self.cart
}
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return productMap.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return productMap[section]?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let product = productMap[indexPath.section]![indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "ProductTableViewCell") as! ProductTableViewCell
cell.imageView?.image = product.imagename
cell.delegate = self as CartDelegate
cell.setButton(state: self.cart.contains(product: product))
return cell
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 44
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
switch(section) {
case 0: return "Section A"
case 1: return "Section B"
case 2: return "Section C"
case 3: return "Section D"
case 4: return "Section E"
case 5: return "Section F"
case 6: return "Section G"
case 7: return "Section H"
case 8: return "Section I"
case 9: return "Section J"
case 10: return "Section K"
case 11: return "Section L"
default: return ""
}
}
}
extension ProductViewController: CartDelegate {
// MARK: - CartDelegate
func updateCart(cell: ProductTableViewCell) {
guard let indexPath = tableView.indexPath(for: cell) else { return }
let product = productMap[indexPath.section]![indexPath.row]
//Update Cart with product
cart.updateCart(with: product)
// self.navigationItem.rightBarButtonItem?.title = "Checkout (\(cart.items.count))"
notificationButton.badge = String(cart.items.count) // making badge equal to noofitems in cart
}
}
***// Most relevant code begins here -***
extension ProductViewController {
@IBAction func buttonHandlerAddToCart(_ sender: UIButton) {
let buttonPosition : CGPoint = sender.convert(sender.bounds.origin, to: self.tableView)
let indexPath = self.tableView.indexPathForRow(at: buttonPosition)!
let cell = tableView.cellForRow(at: indexPath) as! ProductTableViewCell
let imageViewPosition : CGPoint = cell.imageView!.convert(cell.imageView!.bounds.origin, to: self.view)
let imgViewTemp = UIImageView(frame: CGRect(x: imageViewPosition.x, y: imageViewPosition.y, width: cell.imageView!.frame.size.width, height: cell.imageView!.frame.size.height))
imgViewTemp.image = cell.imageView!.image
animation(tempView: imgViewTemp)
}
func animation(tempView : UIView) {
self.view.addSubview(tempView)
UIView.animate(
withDuration: 1.0,
animations: {
tempView.animationZoom(scaleX: 1.5, y: 1.5)
}, completion: { _ in
UIView.animate(withDuration: 0.5, animations: {
tempView.animationZoom(scaleX: 0.2, y: 0.2)
tempView.animationRoted(angle: CGFloat(Double.pi))
tempView.frame.origin.x = self.notificationButton.frame.origin.x
tempView.frame.origin.y = self.notificationButton.frame.origin.y
}, completion: { _ in
tempView.removeFromSuperview()
UIView.animate(withDuration: 1.0, animations: {
self.notificationButton.animationZoom(scaleX: 1.4, y: 1.4)
}, completion: {_ in
self.notificationButton.animationZoom(scaleX: 1.0, y: 1.0)
})
})
}
)
}
}
extension UIView{
func animationZoom(scaleX: CGFloat, y: CGFloat) {
self.transform = CGAffineTransform(scaleX: scaleX, y: y)
}
func animationRoted(angle : CGFloat) {
self.transform = self.transform.rotated(by: angle)
}
}
我还包含了 ProductTableViewCell 代码,以防万一:
import UIKit
protocol CartDelegate {
func updateCart(cell: ProductTableViewCell)
}
class ProductTableViewCell: UITableViewCell {
weak var myParent:ProductViewController?
@IBOutlet weak var imagename: UIImageView!
@IBOutlet weak var addToCartButton: UIButton!
var delegate: CartDelegate?
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
addToCartButton.layer.cornerRadius = 5
addToCartButton.clipsToBounds = true
}
func setButton(state: Bool) {
addToCartButton.isUserInteractionEnabled = true
addToCartButton.isSelected = state
addToCartButton.backgroundColor = (!addToCartButton.isSelected) ? .blue : .red
}
@IBAction func addToCart(_ sender: Any) {
setButton(state: !addToCartButton.isSelected)
self.delegate?.updateCart(cell: self)
}
}
编辑:应@aheze 的要求:
struct Product: Equatable {
let imagename: UIImage
}
var productMap = [
0: [ Product(imagename:#imageLiteral(resourceName: "blue")), Product( imagename:#imageLiteral(resourceName: "CakeImage")) ]
1: [ Product(imagename:#imageLiteral(resourceName: "vectorlogo")), Product(imagename:#imageLiteral(resourceName: "PeasImge")), Product(imagename:#imageLiteral(resourceName: "castle"))],
2: [ Product( imagename:#imageLiteral(resourceName: "scoobydoo")),Product(imagename:#imageLiteral(resourceName: "ufo"))] ,
3: [ Product( imagename:#imageLiteral(resourceName: "wolfsky")),Product( imagename:#imageLiteral(resourceName: "universe")) ],
4: [ Product(imagename:#imageLiteral(resourceName: "werewolf")),Product( imagename:#imageLiteral(resourceName: "galaxy")) ]
]
编辑 2:Cart 类,应 @aheze 的要求:
import Foundation
class Cart {
var items : [CartItem] = []
}
extension Cart {
var totalQuantity : Int {
get { return items.reduce(0) { value, item in
value + item.quantity
}
}
}
func updateCart(with product: Product) {
if !self.contains(product: product) {
self.add(product: product)
} else {
self.remove(product: product)
}
}
func updateCart() {
for item in self.items {
if item.quantity == 0 {
updateCart(with: item.product)
}
}
}
func add(product: Product) {
let item = items.filter { $0.product == product }
if item.first != nil {
item.first!.quantity += 1
} else {
items.append(CartItem(product: product))
}
}
func remove(product: Product) {
guard let index = items.firstIndex(where: { $0.product == product }) else { return}
items.remove(at: index)
}
func contains(product: Product) -> Bool {
let item = items.filter { $0.product == product }
return item.first != nil
}
}
您需要更多信息,请随时...
【问题讨论】:
-
如您所见,就声誉而言,我在镇上有点穷,但由于时间紧迫,我仍然提供了赏金。请调查此事。
-
您能说明
productMap的定义位置吗? -
抱歉回复晚了。请参阅编辑。
-
但据我所知,它与 productMap 无关。它必须与 ProductTableViewCell 和/或 ProductViewController 中的标记按钮,并在 ProductViewController 中反转完成汉斯勒。
-
谢谢。为了跟踪选择了哪个产品,您应该创建一个新数组
selectedProducts,并在选择产品时将产品附加到该数组中。然后,您可以检查其中有哪些产品,并调整动画。要反转,我建议只制作一个新的动画功能。我现在需要去,但我明天会尝试发布一些代码
标签: ios swift uitableview