Repository: 6ag/shoppingCart
Branch: master
Commit: 1bbe1a0e227d
Files: 50
Total size: 151.8 KB
Directory structure:
gitextract_3739o5f2/
├── README.md
├── shoppingCart/
│ ├── AppDelegate.swift
│ ├── Assets.xcassets/
│ │ ├── AppIcon.appiconset/
│ │ │ └── Contents.json
│ │ ├── Contents.json
│ │ ├── add_icon.imageset/
│ │ │ └── Contents.json
│ │ ├── button_cart.imageset/
│ │ │ └── Contents.json
│ │ ├── button_cart_add.imageset/
│ │ │ └── Contents.json
│ │ ├── check_n.imageset/
│ │ │ └── Contents.json
│ │ ├── check_y.imageset/
│ │ │ └── Contents.json
│ │ ├── delete_icon.imageset/
│ │ │ └── Contents.json
│ │ ├── goodicon_0.imageset/
│ │ │ └── Contents.json
│ │ ├── goodicon_1.imageset/
│ │ │ └── Contents.json
│ │ ├── goodicon_2.imageset/
│ │ │ └── Contents.json
│ │ ├── goodicon_3.imageset/
│ │ │ └── Contents.json
│ │ ├── goodicon_4.imageset/
│ │ │ └── Contents.json
│ │ ├── goodicon_5.imageset/
│ │ │ └── Contents.json
│ │ ├── goodicon_6.imageset/
│ │ │ └── Contents.json
│ │ ├── goodicon_7.imageset/
│ │ │ └── Contents.json
│ │ ├── goodicon_8.imageset/
│ │ │ └── Contents.json
│ │ ├── goodicon_9.imageset/
│ │ │ └── Contents.json
│ │ ├── numbe_bg_icon.imageset/
│ │ │ └── Contents.json
│ │ └── subtraction_icon.imageset/
│ │ └── Contents.json
│ ├── Base.lproj/
│ │ └── LaunchScreen.storyboard
│ ├── Classes/
│ │ ├── GoodList/
│ │ │ ├── Controller/
│ │ │ │ └── JFGoodListViewController.swift
│ │ │ └── View/
│ │ │ └── JFGoodListCell.swift
│ │ ├── Library/
│ │ │ └── SnapKit/
│ │ │ ├── Constraint.swift
│ │ │ ├── ConstraintAttributes.swift
│ │ │ ├── ConstraintDescription.swift
│ │ │ ├── ConstraintItem.swift
│ │ │ ├── ConstraintMaker.swift
│ │ │ ├── ConstraintRelation.swift
│ │ │ ├── Debugging.swift
│ │ │ ├── EdgeInsets.swift
│ │ │ ├── LayoutConstraint.swift
│ │ │ ├── SnapKit.h
│ │ │ ├── SnapKit.swift
│ │ │ ├── SourceLocation.swift
│ │ │ ├── View+SnapKit.swift
│ │ │ └── ViewController+SnapKit.swift
│ │ ├── Model/
│ │ │ └── JFGoodModel.swift
│ │ └── ShopCart/
│ │ ├── Controller/
│ │ │ └── JFShoppingCartViewController.swift
│ │ └── View/
│ │ ├── JFOldPriceLabel.swift
│ │ └── JFShoppingCartCell.swift
│ └── Info.plist
└── shoppingCart.xcodeproj/
├── project.pbxproj
├── project.xcworkspace/
│ ├── contents.xcworkspacedata
│ └── xcuserdata/
│ └── jianfeng.xcuserdatad/
│ └── UserInterfaceState.xcuserstate
└── xcuserdata/
└── jianfeng.xcuserdatad/
├── xcdebugger/
│ └── Breakpoints_v2.xcbkptlist
└── xcschemes/
├── shoppingCart.xcscheme
└── xcschememanagement.plist
================================================
FILE CONTENTS
================================================
================================================
FILE: README.md
================================================
# shoppingCart
## swift的购物车demo
采用纯代码UI,autolayout自动布局,core animation动画效果。

================================================
FILE: shoppingCart/AppDelegate.swift
================================================
//
// AppDelegate.swift
// shoppingCart
//
// Created by jianfeng on 15/11/17.
// Copyright © 2015年 六阿哥. All rights reserved.
//
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// 手动创建window
window = UIWindow(frame: UIScreen.mainScreen().bounds)
// 设置window的根控制器
window?.rootViewController = UINavigationController(rootViewController: JFGoodListViewController())
// 设置window为主window并显示在窗口
window?.makeKeyAndVisible()
return true
}
func applicationWillResignActive(application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
func applicationDidEnterBackground(application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(application: UIApplication) {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}
================================================
FILE: shoppingCart/Assets.xcassets/AppIcon.appiconset/Contents.json
================================================
{
"images" : [
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: shoppingCart/Assets.xcassets/Contents.json
================================================
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: shoppingCart/Assets.xcassets/add_icon.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "add_icon@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: shoppingCart/Assets.xcassets/button_cart.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "button_cart@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: shoppingCart/Assets.xcassets/button_cart_add.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "button_add_cart.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: shoppingCart/Assets.xcassets/check_n.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "check_n@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: shoppingCart/Assets.xcassets/check_y.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "check_p@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: shoppingCart/Assets.xcassets/delete_icon.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "delete_icon@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: shoppingCart/Assets.xcassets/goodicon_0.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "goodicon_0.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: shoppingCart/Assets.xcassets/goodicon_1.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "goodicon_1.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: shoppingCart/Assets.xcassets/goodicon_2.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "goodicon_2.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: shoppingCart/Assets.xcassets/goodicon_3.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "goodicon_3.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: shoppingCart/Assets.xcassets/goodicon_4.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "goodicon_4.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: shoppingCart/Assets.xcassets/goodicon_5.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "goodicon_5.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: shoppingCart/Assets.xcassets/goodicon_6.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "goodicon_6.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: shoppingCart/Assets.xcassets/goodicon_7.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "goodicon_7.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: shoppingCart/Assets.xcassets/goodicon_8.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "goodicon_8.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: shoppingCart/Assets.xcassets/goodicon_9.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "goodicon_9.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: shoppingCart/Assets.xcassets/numbe_bg_icon.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "numbe_bg_icon@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: shoppingCart/Assets.xcassets/subtraction_icon.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "jian_icon@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: shoppingCart/Base.lproj/LaunchScreen.storyboard
================================================
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="9059" systemVersion="15B42" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" initialViewController="01J-lp-oVM">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9049"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/>
<viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<animations/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-414" y="382"/>
</scene>
</scenes>
</document>
================================================
FILE: shoppingCart/Classes/GoodList/Controller/JFGoodListViewController.swift
================================================
//
// JFGoodListViewController.swift
// shoppingCart
//
// Created by jianfeng on 15/11/17.
// Copyright © 2015年 六阿哥. All rights reserved.
//
import UIKit
// 屏幕尺寸
let SCREEN_WIDTH = UIScreen.mainScreen().bounds.size.width
let SCREEN_HEIGHT = UIScreen.mainScreen().bounds.size.height
class JFGoodListViewController: UIViewController {
// MARK: - 属性
/// 商品模型数组,初始化
private var goodArray = [JFGoodModel]()
/// 商品列表cell的重用标识符
private let goodListCellIdentifier = "goodListCell"
/// 已经添加进购物车的商品模型数组,初始化
private var addGoodArray = [JFGoodModel]()
/// 贝塞尔曲线
private var path: UIBezierPath?
/// 自定义图层
var layer: CALayer?
// MARK: - view生命周期
override func viewDidLoad() {
super.viewDidLoad()
// 提醒:这个方法中一般用于初始化控制器中的一些数据、添加子控件等。但是这个方法获取的frame并不一定准确,所以不建议在这个方法约束子控件
// 初始化模型数组,也就是搞点假数据。这里整10个模型
for i in 0..<10 {
var dict = [String : AnyObject]()
dict["iconName"] = "goodicon_\(i)"
dict["title"] = "\(i + 1)阿哥"
dict["desc"] = "这是第\(i + 1)个商品"
dict["newPrice"] = "1000\(i)"
dict["oldPrice"] = "2000\(i)"
// 字典转模型并将模型添加到模型数组中
goodArray.append(JFGoodModel(dict: dict))
}
// 准备子控件
prepareUI()
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
// 提示:这个方法是在控制器view已经显示后调用,我们可以在这个方法里面做一些子控件约束操作等
// 约束子控件
layoutUI()
}
/**
准备子控件方法,在这个方法中我们可以创建并添加子控件到view
*/
private func prepareUI() {
// 标题
navigationItem.title = "商品列表"
// 添加导航栏上的购物车按钮和已经添加的商品数量label
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: cartButton)
// 添加购物车按钮上的label
navigationController?.navigationBar.addSubview(addCountLabel)
navigationController?.navigationBar.barTintColor = UIColor.whiteColor()
// 添加tableView到控制器的view上
view.addSubview(tableView)
// 注册cell
tableView.registerClass(JFGoodListCell.self, forCellReuseIdentifier: goodListCellIdentifier)
}
/**
约束子控件的方法
*/
private func layoutUI() {
// 约束tableview,让它全屏显示。注意:这里我使用了第三方约束框架(SnapKit)。如果还不会使用,请学习
tableView.snp_makeConstraints { (make) -> Void in
make.edges.equalTo(view.snp_edges)
}
addCountLabel.snp_makeConstraints { (make) -> Void in
make.right.equalTo(-12)
make.top.equalTo(10.5)
make.width.equalTo(15)
make.height.equalTo(15)
}
}
// MARK: - 懒加载
/// tableView
lazy var tableView: UITableView = {
let tableView = UITableView()
tableView.rowHeight = 80
// 指定数据源和代理
tableView.dataSource = self
tableView.delegate = self
return tableView
}()
/// cartButton顶部购物车按钮
lazy var cartButton: UIButton = {
let carButton = UIButton(type: UIButtonType.Custom)
carButton.setImage(UIImage(named: "button_cart"), forState: UIControlState.Normal)
carButton.addTarget(self, action: "didTappedCarButton:", forControlEvents: UIControlEvents.TouchUpInside)
carButton.sizeToFit()
return carButton
}()
/// 已经添加进购物车的商品数量
lazy var addCountLabel: UILabel = {
let addCountLabel = UILabel()
addCountLabel.backgroundColor = UIColor.whiteColor()
addCountLabel.textColor = UIColor.redColor()
addCountLabel.font = UIFont.boldSystemFontOfSize(11)
addCountLabel.textAlignment = NSTextAlignment.Center
addCountLabel.text = "\(self.addGoodArray.count)"
addCountLabel.layer.cornerRadius = 7.5
addCountLabel.layer.masksToBounds = true
addCountLabel.layer.borderWidth = 1
addCountLabel.layer.borderColor = UIColor.redColor().CGColor
addCountLabel.hidden = true
return addCountLabel
}()
}
// MARK: - UITableViewDataSource, UITableViewDelegate 数据源和代理方法
extension JFGoodListViewController: UITableViewDataSource, UITableViewDelegate {
// 第section组有多少个cell,我们这里一共就一组。所以直接返回模型数组的长度
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return goodArray.count
}
// 创建每个cell
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// 从缓存池创建cell,如果没有从缓存池创建成功就根据注册的cell重用标识符创建一个新的cell
let cell = tableView.dequeueReusableCellWithIdentifier(goodListCellIdentifier, forIndexPath: indexPath) as! JFGoodListCell
// 取消选中效果
cell.selectionStyle = UITableViewCellSelectionStyle.None
// 为cell传递数据
cell.goodModel = goodArray[indexPath.row]
// 指定代理
cell.delegate = self
// 返回创建好的cell
return cell
}
}
// view上的一些事件处理在这个类扩展里
extension JFGoodListViewController {
/**
当点击了购物车触发,modal到购物车控制器
- parameter button: 购物车按钮
*/
@objc private func didTappedCarButton(button: UIButton) {
let shoppingCartVc = JFShoppingCartViewController()
// 传递商品模型数组
shoppingCartVc.addGoodArray = addGoodArray
// 模态出一个购物车控制器
presentViewController(UINavigationController(rootViewController: shoppingCartVc), animated: true, completion: nil)
}
}
// MARK: - JFGoodListCellDelegate代理方法
extension JFGoodListViewController: JFGoodListCellDelegate {
/**
代理回调方法,当点击了cell上的购买按钮后触发
- parameter cell: 被点击的cell
- parameter iconView: 被点击的cell上的图标对象
*/
func goodListCell(cell: JFGoodListCell, iconView: UIImageView) {
guard let indexPath = tableView.indexPathForCell(cell) else {
return
}
// 获取当前模型,添加到购物车模型数组
let model = goodArray[indexPath.row]
addGoodArray.append(model)
// 重新计算iconView的frame,并开启动画
var rect = tableView .rectForRowAtIndexPath(indexPath)
rect.origin.y -= tableView.contentOffset.y
var headRect = iconView.frame
headRect.origin.y = rect.origin.y + headRect.origin.y - 64
startAnimation(headRect, iconView: iconView)
}
}
// MARK: - 商品图片抛入购物车的动画效果
extension JFGoodListViewController {
/**
开始动画
- parameter rect: 商品图标对象的frame
- parameter iconView: 商品图标对象
*/
private func startAnimation(rect: CGRect, iconView: UIImageView) {
if layer == nil {
layer = CALayer()
layer?.contents = iconView.layer.contents
layer?.contentsGravity = kCAGravityResizeAspectFill
layer?.bounds = rect
layer?.cornerRadius = CGRectGetHeight(layer!.bounds) * 0.5
layer?.masksToBounds = true
layer?.position = CGPoint(x: iconView.center.x, y: CGRectGetMinY(rect) + 96)
UIApplication.sharedApplication().keyWindow?.layer.addSublayer(layer!)
path = UIBezierPath()
path!.moveToPoint(layer!.position)
path!.addQuadCurveToPoint(CGPoint(x: SCREEN_WIDTH - 25, y: 35), controlPoint: CGPoint(x: SCREEN_WIDTH * 0.5, y: rect.origin.y - 80))
}
// 组动画
groupAnimation()
}
/**
组动画,帧动画抛入购物车,并放大、缩小图层增加点动效。
*/
private func groupAnimation() {
// 开始动画禁用tableview交互
tableView.userInteractionEnabled = false
// 帧动画
let animation = CAKeyframeAnimation(keyPath: "position")
animation.path = path!.CGPath
animation.rotationMode = kCAAnimationRotateAuto
// 放大动画
let bigAnimation = CABasicAnimation(keyPath: "transform.scale")
bigAnimation.duration = 0.5
bigAnimation.fromValue = 1
bigAnimation.toValue = 2
bigAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn)
// 缩小动画
let smallAnimation = CABasicAnimation(keyPath: "transform.scale")
smallAnimation.beginTime = 0.5
smallAnimation.duration = 1.5
smallAnimation.fromValue = 2
smallAnimation.toValue = 0.3
smallAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
// 组动画
let groupAnimation = CAAnimationGroup()
groupAnimation.animations = [animation, bigAnimation, smallAnimation]
groupAnimation.duration = 2
groupAnimation.removedOnCompletion = false
groupAnimation.fillMode = kCAFillModeForwards
groupAnimation.delegate = self
layer?.addAnimation(groupAnimation, forKey: "groupAnimation")
}
/**
动画结束后做一些操作
*/
override func animationDidStop(anim: CAAnimation, finished flag: Bool) {
// 如果动画是我们的组动画,才开始一些操作
if anim == layer?.animationForKey("groupAnimation") {
// 开启交互
tableView.userInteractionEnabled = true
// 隐藏图层
layer?.removeAllAnimations()
layer?.removeFromSuperlayer()
layer = nil
// 如果商品数大于0,显示购物车里的商品数量
if self.addGoodArray.count > 0 {
addCountLabel.hidden = false
}
// 商品数量渐出
let goodCountAnimation = CATransition()
goodCountAnimation.duration = 0.25
addCountLabel.text = "\(self.addGoodArray.count)"
addCountLabel.layer.addAnimation(goodCountAnimation, forKey: nil)
// 购物车抖动
let cartAnimation = CABasicAnimation(keyPath: "transform.translation.y")
cartAnimation.duration = 0.25
cartAnimation.fromValue = -5
cartAnimation.toValue = 5
cartAnimation.autoreverses = true
cartButton.layer.addAnimation(cartAnimation, forKey: nil)
}
}
}
================================================
FILE: shoppingCart/Classes/GoodList/View/JFGoodListCell.swift
================================================
//
// JFGoodListCell.swift
// shoppingCart
//
// Created by jianfeng on 15/11/17.
// Copyright © 2015年 六阿哥. All rights reserved.
//
import UIKit
protocol JFGoodListCellDelegate: NSObjectProtocol {
func goodListCell(cell: JFGoodListCell, iconView: UIImageView)
}
class JFGoodListCell: UITableViewCell {
// MARK: - 属性
/// 商品模型
var goodModel: JFGoodModel? {
didSet {
if let iconName = goodModel?.iconName {
iconView.image = UIImage(named: iconName)
}
if let title = goodModel?.title {
titleLabel.text = title
}
if let desc = goodModel?.desc {
descLabel.text = desc
}
// 已经点击的就禁用,这样做是防止cell重用
addCartButton.enabled = !goodModel!.alreadyAddShoppingCart
// 重新布局,会更新frame
layoutIfNeeded()
}
}
/// 代理属性
weak var delegate: JFGoodListCellDelegate?
/// 回调给控制器的商品图标
var callBackIconView: UIImageView?
// MARK: - 构造方法
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
// 准备UI
prepareUI()
}
/**
准备UI
*/
private func prepareUI() {
// 添加子控件
contentView.addSubview(iconView)
contentView.addSubview(titleLabel)
contentView.addSubview(descLabel)
contentView.addSubview(addCartButton)
// 约束子控件
iconView.snp_makeConstraints { (make) -> Void in
make.left.equalTo(12)
make.top.equalTo(10)
make.width.equalTo(60)
make.height.equalTo(60)
}
titleLabel.snp_makeConstraints { (make) -> Void in
make.top.equalTo(contentView.snp_top).offset(10)
make.left.equalTo(iconView.snp_right).offset(12)
}
descLabel.snp_makeConstraints { (make) -> Void in
make.top.equalTo(titleLabel.snp_bottom).offset(12)
make.left.equalTo(iconView.snp_right).offset(12)
}
addCartButton.snp_makeConstraints { (make) -> Void in
make.right.equalTo(-12)
make.top.equalTo(25)
make.width.equalTo(80)
make.height.equalTo(30)
}
}
// MARK: - 响应事件
/**
点击了购买按钮的事件
- parameter button: 购买按钮
*/
@objc private func didTappedAddCartButton(button: UIButton) {
// 已经购买
goodModel!.alreadyAddShoppingCart = true
// 已经点击的就禁用
button.enabled = !goodModel!.alreadyAddShoppingCart
// 通知代理对象,去处理后续操作
delegate?.goodListCell(self, iconView: iconView)
}
// MARK: - 懒加载
/// 商品图片
private lazy var iconView: UIImageView = {
let iconView = UIImageView()
iconView.layer.cornerRadius = 30
iconView.layer.masksToBounds = true
return iconView
}()
/// 商品标题
private lazy var titleLabel: UILabel = {
let titleLabel = UILabel()
return titleLabel
}()
/// 商品描述
private lazy var descLabel: UILabel = {
let descLabel = UILabel()
descLabel.textColor = UIColor.grayColor()
return descLabel
}()
/// 添加按钮
private lazy var addCartButton: UIButton = {
let addCartButton = UIButton(type: UIButtonType.Custom)
addCartButton.setBackgroundImage(UIImage(named: "button_cart_add"), forState: UIControlState.Normal)
addCartButton.setTitle("购买", forState: UIControlState.Normal)
// 添加按钮点击事件
addCartButton.addTarget(self, action: "didTappedAddCartButton:", forControlEvents: UIControlEvents.TouchUpInside)
return addCartButton
}()
}
================================================
FILE: shoppingCart/Classes/Library/SnapKit/Constraint.swift
================================================
//
// SnapKit
//
// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
/**
Used to expose API's for a Constraint
*/
public class Constraint {
public func install() -> [LayoutConstraint] { fatalError("Must be implemented by Concrete subclass.") }
public func uninstall() -> Void { fatalError("Must be implemented by Concrete subclass.") }
public func activate() -> Void { fatalError("Must be implemented by Concrete subclass.") }
public func deactivate() -> Void { fatalError("Must be implemented by Concrete subclass.") }
public func updateOffset(amount: Float) -> Void { fatalError("Must be implemented by Concrete subclass.") }
public func updateOffset(amount: Double) -> Void { fatalError("Must be implemented by Concrete subclass.") }
public func updateOffset(amount: CGFloat) -> Void { fatalError("Must be implemented by Concrete subclass.") }
public func updateOffset(amount: Int) -> Void { fatalError("Must be implemented by Concrete subclass.") }
public func updateOffset(amount: UInt) -> Void { fatalError("Must be implemented by Concrete subclass.") }
public func updateOffset(amount: CGPoint) -> Void { fatalError("Must be implemented by Concrete subclass.") }
public func updateOffset(amount: CGSize) -> Void { fatalError("Must be implemented by Concrete subclass.") }
public func updateOffset(amount: EdgeInsets) -> Void { fatalError("Must be implemented by Concrete subclass.") }
public func updateInsets(amount: EdgeInsets) -> Void { fatalError("Must be implemented by Concrete subclass.") }
public func updatePriority(priority: Float) -> Void { fatalError("Must be implemented by Concrete subclass.") }
public func updatePriority(priority: Double) -> Void { fatalError("Must be implemented by Concrete subclass.") }
public func updatePriority(priority: CGFloat) -> Void { fatalError("Must be implemented by Concrete subclass.") }
public func updatePriority(priority: UInt) -> Void { fatalError("Must be implemented by Concrete subclass.") }
public func updatePriority(priority: Int) -> Void { fatalError("Must be implemented by Concrete subclass.") }
public func updatePriorityRequired() -> Void { fatalError("Must be implemented by Concrete subclass.") }
public func updatePriorityHigh() -> Void { fatalError("Must be implemented by Concrete subclass.") }
public func updatePriorityMedium() -> Void { fatalError("Must be implemented by Concrete subclass.") }
public func updatePriorityLow() -> Void { fatalError("Must be implemented by Concrete subclass.") }
internal var makerLocation: SourceLocation = SourceLocation(file: "Unknown", line: 0)
internal(set) public var location: SourceLocation?
}
/**
Used internally to implement a ConcreteConstraint
*/
internal class ConcreteConstraint: Constraint {
internal override func updateOffset(amount: Float) -> Void {
self.constant = amount
}
internal override func updateOffset(amount: Double) -> Void {
self.updateOffset(Float(amount))
}
internal override func updateOffset(amount: CGFloat) -> Void {
self.updateOffset(Float(amount))
}
internal override func updateOffset(amount: Int) -> Void {
self.updateOffset(Float(amount))
}
internal override func updateOffset(amount: UInt) -> Void {
self.updateOffset(Float(amount))
}
internal override func updateOffset(amount: CGPoint) -> Void {
self.constant = amount
}
internal override func updateOffset(amount: CGSize) -> Void {
self.constant = amount
}
internal override func updateOffset(amount: EdgeInsets) -> Void {
self.constant = amount
}
internal override func updateInsets(amount: EdgeInsets) -> Void {
self.constant = EdgeInsets(top: amount.top, left: amount.left, bottom: -amount.bottom, right: -amount.right)
}
internal override func updatePriority(priority: Float) -> Void {
self.priority = priority
}
internal override func updatePriority(priority: Double) -> Void {
self.updatePriority(Float(priority))
}
internal override func updatePriority(priority: CGFloat) -> Void {
self.updatePriority(Float(priority))
}
internal override func updatePriority(priority: UInt) -> Void {
self.updatePriority(Float(priority))
}
internal override func updatePriority(priority: Int) -> Void {
self.updatePriority(Float(priority))
}
internal override func updatePriorityRequired() -> Void {
self.updatePriority(Float(1000.0))
}
internal override func updatePriorityHigh() -> Void {
self.updatePriority(Float(750.0))
}
internal override func updatePriorityMedium() -> Void {
#if os(iOS) || os(tvOS)
self.updatePriority(Float(500.0))
#else
self.updatePriority(Float(501.0))
#endif
}
internal override func updatePriorityLow() -> Void {
self.updatePriority(Float(250.0))
}
internal override func install() -> [LayoutConstraint] {
return self.installOnView(updateExisting: false, location: self.makerLocation)
}
internal override func uninstall() -> Void {
self.uninstallFromView()
}
internal override func activate() -> Void {
guard self.installInfo != nil else {
self.install()
return
}
#if SNAPKIT_DEPLOYMENT_LEGACY
guard #available(iOS 8.0, OSX 10.10, *) else {
self.install()
return
}
#endif
let layoutConstraints = self.installInfo!.layoutConstraints.allObjects as! [LayoutConstraint]
if layoutConstraints.count > 0 {
NSLayoutConstraint.activateConstraints(layoutConstraints)
}
}
internal override func deactivate() -> Void {
guard self.installInfo != nil else {
return
}
#if SNAPKIT_DEPLOYMENT_LEGACY
guard #available(iOS 8.0, OSX 10.10, *) else {
return
}
#endif
let layoutConstraints = self.installInfo!.layoutConstraints.allObjects as! [LayoutConstraint]
if layoutConstraints.count > 0 {
NSLayoutConstraint.deactivateConstraints(layoutConstraints)
}
}
private let fromItem: ConstraintItem
private let toItem: ConstraintItem
private let relation: ConstraintRelation
private let multiplier: Float
private var constant: Any {
didSet {
if let installInfo = self.installInfo {
for layoutConstraint in installInfo.layoutConstraints.allObjects as! [LayoutConstraint] {
let attribute = (layoutConstraint.secondAttribute == .NotAnAttribute) ? layoutConstraint.firstAttribute : layoutConstraint.secondAttribute
layoutConstraint.constant = attribute.snp_constantForValue(self.constant)
}
}
}
}
private var priority: Float {
didSet {
if let installInfo = self.installInfo {
for layoutConstraint in installInfo.layoutConstraints.allObjects as! [LayoutConstraint] {
layoutConstraint.priority = self.priority
}
}
}
}
private var installInfo: ConcreteConstraintInstallInfo? = nil
internal init(fromItem: ConstraintItem, toItem: ConstraintItem, relation: ConstraintRelation, constant: Any, multiplier: Float, priority: Float, location: SourceLocation?) {
self.fromItem = fromItem
self.toItem = toItem
self.relation = relation
self.constant = constant
self.multiplier = multiplier
self.priority = priority
super.init()
self.location = location
}
internal func installOnView(updateExisting updateExisting: Bool = false, location: SourceLocation? = nil) -> [LayoutConstraint] {
var installOnView: View? = nil
if self.toItem.view != nil {
installOnView = closestCommonSuperviewFromView(self.fromItem.view, toView: self.toItem.view)
if installOnView == nil {
NSException(name: "Cannot Install Constraint", reason: "No common superview between views (@\(self.makerLocation.file)#\(self.makerLocation.line))", userInfo: nil).raise()
return []
}
} else {
if self.fromItem.attributes.isSubsetOf(ConstraintAttributes.Width.union(.Height)) {
installOnView = self.fromItem.view
} else {
installOnView = self.fromItem.view?.superview
if installOnView == nil {
NSException(name: "Cannot Install Constraint", reason: "Missing superview (@\(self.makerLocation.file)#\(self.self.makerLocation.line))", userInfo: nil).raise()
return []
}
}
}
if let installedOnView = self.installInfo?.view {
if installedOnView != installOnView {
NSException(name: "Cannot Install Constraint", reason: "Already installed on different view. (@\(self.makerLocation.file)#\(self.makerLocation.line))", userInfo: nil).raise()
return []
}
return self.installInfo?.layoutConstraints.allObjects as? [LayoutConstraint] ?? []
}
var newLayoutConstraints = [LayoutConstraint]()
let layoutFromAttributes = self.fromItem.attributes.layoutAttributes
let layoutToAttributes = self.toItem.attributes.layoutAttributes
// get layout from
let layoutFrom: View? = self.fromItem.view
// get layout relation
let layoutRelation: NSLayoutRelation = self.relation.layoutRelation
for layoutFromAttribute in layoutFromAttributes {
// get layout to attribute
let layoutToAttribute = (layoutToAttributes.count > 0) ? layoutToAttributes[0] : layoutFromAttribute
// get layout constant
let layoutConstant: CGFloat = layoutToAttribute.snp_constantForValue(self.constant)
// get layout to
#if os(iOS) || os(tvOS)
var layoutTo: AnyObject? = self.toItem.view ?? self.toItem.layoutSupport
#else
var layoutTo: AnyObject? = self.toItem.view
#endif
if layoutTo == nil && layoutToAttribute != .Width && layoutToAttribute != .Height {
layoutTo = installOnView
}
// create layout constraint
let layoutConstraint = LayoutConstraint(
item: layoutFrom!,
attribute: layoutFromAttribute,
relatedBy: layoutRelation,
toItem: layoutTo,
attribute: layoutToAttribute,
multiplier: CGFloat(self.multiplier),
constant: layoutConstant)
// set priority
layoutConstraint.priority = self.priority
// set constraint
layoutConstraint.snp_constraint = self
newLayoutConstraints.append(layoutConstraint)
}
// special logic for updating
if updateExisting {
// get existing constraints for this view
let existingLayoutConstraints = layoutFrom!.snp_installedLayoutConstraints.reverse()
// array that will contain only new layout constraints to keep
var newLayoutConstraintsToKeep = [LayoutConstraint]()
// begin looping
for layoutConstraint in newLayoutConstraints {
// layout constraint that should be updated
var updateLayoutConstraint: LayoutConstraint? = nil
// loop through existing and check for match
for existingLayoutConstraint in existingLayoutConstraints {
if existingLayoutConstraint == layoutConstraint {
updateLayoutConstraint = existingLayoutConstraint
break
}
}
// if we have existing one lets just update the constant
if updateLayoutConstraint != nil {
updateLayoutConstraint!.constant = layoutConstraint.constant
}
// otherwise add this layout constraint to new keep list
else {
newLayoutConstraintsToKeep.append(layoutConstraint)
}
}
// set constraints to only new ones
newLayoutConstraints = newLayoutConstraintsToKeep
}
// add constraints
#if SNAPKIT_DEPLOYMENT_LEGACY && !os(OSX)
if #available(iOS 8.0, *) {
NSLayoutConstraint.activateConstraints(newLayoutConstraints)
} else {
installOnView!.addConstraints(newLayoutConstraints)
}
#else
NSLayoutConstraint.activateConstraints(newLayoutConstraints)
#endif
// set install info
self.installInfo = ConcreteConstraintInstallInfo(view: installOnView, layoutConstraints: NSHashTable.weakObjectsHashTable())
// store which layout constraints are installed for this constraint
for layoutConstraint in newLayoutConstraints {
self.installInfo!.layoutConstraints.addObject(layoutConstraint)
}
// store the layout constraints against the layout from view
layoutFrom!.snp_installedLayoutConstraints += newLayoutConstraints
// return the new constraints
return newLayoutConstraints
}
internal func uninstallFromView() {
if let installInfo = self.installInfo,
let installedLayoutConstraints = installInfo.layoutConstraints.allObjects as? [LayoutConstraint] {
if installedLayoutConstraints.count > 0 {
// remove the constraints from the UIView's storage
#if SNAPKIT_DEPLOYMENT_LEGACY && !os(OSX)
if #available(iOS 8.0, *) {
NSLayoutConstraint.deactivateConstraints(installedLayoutConstraints)
} else if let installedOnView = installInfo.view {
installedOnView.removeConstraints(installedLayoutConstraints)
}
#else
NSLayoutConstraint.deactivateConstraints(installedLayoutConstraints)
#endif
// remove the constraints from the from item view
if let fromView = self.fromItem.view {
fromView.snp_installedLayoutConstraints = fromView.snp_installedLayoutConstraints.filter {
return !installedLayoutConstraints.contains($0)
}
}
}
}
self.installInfo = nil
}
}
private struct ConcreteConstraintInstallInfo {
weak var view: View? = nil
let layoutConstraints: NSHashTable
}
private extension NSLayoutAttribute {
private func snp_constantForValue(value: Any?) -> CGFloat {
// Float
if let float = value as? Float {
return CGFloat(float)
}
// Double
else if let double = value as? Double {
return CGFloat(double)
}
// UInt
else if let int = value as? Int {
return CGFloat(int)
}
// Int
else if let uint = value as? UInt {
return CGFloat(uint)
}
// CGFloat
else if let float = value as? CGFloat {
return float
}
// CGSize
else if let size = value as? CGSize {
if self == .Width {
return size.width
} else if self == .Height {
return size.height
}
}
// CGPoint
else if let point = value as? CGPoint {
#if os(iOS) || os(tvOS)
switch self {
case .Left, .CenterX, .LeftMargin, .CenterXWithinMargins: return point.x
case .Top, .CenterY, .TopMargin, .CenterYWithinMargins, .Baseline, .FirstBaseline: return point.y
case .Right, .RightMargin: return point.x
case .Bottom, .BottomMargin: return point.y
case .Leading, .LeadingMargin: return point.x
case .Trailing, .TrailingMargin: return point.x
case .Width, .Height, .NotAnAttribute: return CGFloat(0)
}
#else
switch self {
case .Left, .CenterX: return point.x
case .Top, .CenterY, .Baseline: return point.y
case .Right: return point.x
case .Bottom: return point.y
case .Leading: return point.x
case .Trailing: return point.x
case .Width, .Height, .NotAnAttribute: return CGFloat(0)
case .FirstBaseline: return point.y
}
#endif
}
// EdgeInsets
else if let insets = value as? EdgeInsets {
#if os(iOS) || os(tvOS)
switch self {
case .Left, .CenterX, .LeftMargin, .CenterXWithinMargins: return insets.left
case .Top, .CenterY, .TopMargin, .CenterYWithinMargins, .Baseline, .FirstBaseline: return insets.top
case .Right, .RightMargin: return insets.right
case .Bottom, .BottomMargin: return insets.bottom
case .Leading, .LeadingMargin: return (Config.interfaceLayoutDirection == .LeftToRight) ? insets.left : -insets.right
case .Trailing, .TrailingMargin: return (Config.interfaceLayoutDirection == .LeftToRight) ? insets.right : -insets.left
case .Width, .Height, .NotAnAttribute: return CGFloat(0)
}
#else
switch self {
case .Left, .CenterX: return insets.left
case .Top, .CenterY, .Baseline: return insets.top
case .Right: return insets.right
case .Bottom: return insets.bottom
case .Leading: return (Config.interfaceLayoutDirection == .LeftToRight) ? insets.left : -insets.right
case .Trailing: return (Config.interfaceLayoutDirection == .LeftToRight) ? insets.right : -insets.left
case .Width, .Height, .NotAnAttribute: return CGFloat(0)
case .FirstBaseline: return insets.bottom
}
#endif
}
return CGFloat(0);
}
}
private func closestCommonSuperviewFromView(fromView: View?, toView: View?) -> View? {
var views = Set<View>()
var fromView = fromView
var toView = toView
repeat {
if let view = toView {
if views.contains(view) {
return view
}
views.insert(view)
toView = view.superview
}
if let view = fromView {
if views.contains(view) {
return view
}
views.insert(view)
fromView = view.superview
}
} while (fromView != nil || toView != nil)
return nil
}
private func ==(left: ConcreteConstraint, right: ConcreteConstraint) -> Bool {
return (left.fromItem == right.fromItem &&
left.toItem == right.toItem &&
left.relation == right.relation &&
left.multiplier == right.multiplier &&
left.priority == right.priority)
}
================================================
FILE: shoppingCart/Classes/Library/SnapKit/ConstraintAttributes.swift
================================================
//
// SnapKit
//
// Copyright (c) 2011-2015 SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
/**
Used to define `NSLayoutAttributes` in a more concise and composite manner
*/
internal struct ConstraintAttributes: OptionSetType, BooleanType {
internal init(rawValue: UInt) {
self.rawValue = rawValue
}
internal init(_ rawValue: UInt) {
self.init(rawValue: rawValue)
}
internal init(nilLiteral: ()) {
self.rawValue = 0
}
internal private(set) var rawValue: UInt
internal static var allZeros: ConstraintAttributes { return self.init(0) }
internal static func convertFromNilLiteral() -> ConstraintAttributes { return self.init(0) }
internal var boolValue: Bool { return self.rawValue != 0 }
internal func toRaw() -> UInt { return self.rawValue }
internal static func fromRaw(raw: UInt) -> ConstraintAttributes? { return self.init(raw) }
internal static func fromMask(raw: UInt) -> ConstraintAttributes { return self.init(raw) }
// normal
internal static var None: ConstraintAttributes { return self.init(0) }
internal static var Left: ConstraintAttributes { return self.init(1) }
internal static var Top: ConstraintAttributes { return self.init(2) }
internal static var Right: ConstraintAttributes { return self.init(4) }
internal static var Bottom: ConstraintAttributes { return self.init(8) }
internal static var Leading: ConstraintAttributes { return self.init(16) }
internal static var Trailing: ConstraintAttributes { return self.init(32) }
internal static var Width: ConstraintAttributes { return self.init(64) }
internal static var Height: ConstraintAttributes { return self.init(128) }
internal static var CenterX: ConstraintAttributes { return self.init(256) }
internal static var CenterY: ConstraintAttributes { return self.init(512) }
internal static var Baseline: ConstraintAttributes { return self.init(1024) }
@available(iOS 8.0, *)
internal static var FirstBaseline: ConstraintAttributes { return self.init(2048) }
@available(iOS 8.0, *)
internal static var LeftMargin: ConstraintAttributes { return self.init(4096) }
@available(iOS 8.0, *)
internal static var RightMargin: ConstraintAttributes { return self.init(8192) }
@available(iOS 8.0, *)
internal static var TopMargin: ConstraintAttributes { return self.init(16384) }
@available(iOS 8.0, *)
internal static var BottomMargin: ConstraintAttributes { return self.init(32768) }
@available(iOS 8.0, *)
internal static var LeadingMargin: ConstraintAttributes { return self.init(65536) }
@available(iOS 8.0, *)
internal static var TrailingMargin: ConstraintAttributes { return self.init(131072) }
@available(iOS 8.0, *)
internal static var CenterXWithinMargins: ConstraintAttributes { return self.init(262144) }
@available(iOS 8.0, *)
internal static var CenterYWithinMargins: ConstraintAttributes { return self.init(524288) }
// aggregates
internal static var Edges: ConstraintAttributes { return self.init(15) }
internal static var Size: ConstraintAttributes { return self.init(192) }
internal static var Center: ConstraintAttributes { return self.init(768) }
@available(iOS 8.0, *)
internal static var Margins: ConstraintAttributes { return self.init(61440) }
@available(iOS 8.0, *)
internal static var CenterWithinMargins: ConstraintAttributes { return self.init(786432) }
internal var layoutAttributes:[NSLayoutAttribute] {
var attrs = [NSLayoutAttribute]()
if (self.contains(ConstraintAttributes.Left)) {
attrs.append(.Left)
}
if (self.contains(ConstraintAttributes.Top)) {
attrs.append(.Top)
}
if (self.contains(ConstraintAttributes.Right)) {
attrs.append(.Right)
}
if (self.contains(ConstraintAttributes.Bottom)) {
attrs.append(.Bottom)
}
if (self.contains(ConstraintAttributes.Leading)) {
attrs.append(.Leading)
}
if (self.contains(ConstraintAttributes.Trailing)) {
attrs.append(.Trailing)
}
if (self.contains(ConstraintAttributes.Width)) {
attrs.append(.Width)
}
if (self.contains(ConstraintAttributes.Height)) {
attrs.append(.Height)
}
if (self.contains(ConstraintAttributes.CenterX)) {
attrs.append(.CenterX)
}
if (self.contains(ConstraintAttributes.CenterY)) {
attrs.append(.CenterY)
}
if (self.contains(ConstraintAttributes.Baseline)) {
attrs.append(.Baseline)
}
#if os(iOS) || os(tvOS)
#if SNAPKIT_DEPLOYMENT_LEGACY
guard #available(iOS 8.0, *) else {
return attrs
}
#endif
if (self.contains(ConstraintAttributes.FirstBaseline)) {
attrs.append(.FirstBaseline)
}
if (self.contains(ConstraintAttributes.LeftMargin)) {
attrs.append(.LeftMargin)
}
if (self.contains(ConstraintAttributes.RightMargin)) {
attrs.append(.RightMargin)
}
if (self.contains(ConstraintAttributes.TopMargin)) {
attrs.append(.TopMargin)
}
if (self.contains(ConstraintAttributes.BottomMargin)) {
attrs.append(.BottomMargin)
}
if (self.contains(ConstraintAttributes.LeadingMargin)) {
attrs.append(.LeadingMargin)
}
if (self.contains(ConstraintAttributes.TrailingMargin)) {
attrs.append(.TrailingMargin)
}
if (self.contains(ConstraintAttributes.CenterXWithinMargins)) {
attrs.append(.CenterXWithinMargins)
}
if (self.contains(ConstraintAttributes.CenterYWithinMargins)) {
attrs.append(.CenterYWithinMargins)
}
#endif
return attrs
}
}
internal func +=(inout left: ConstraintAttributes, right: ConstraintAttributes) {
left.unionInPlace(right)
}
internal func -=(inout left: ConstraintAttributes, right: ConstraintAttributes) {
left.subtractInPlace(right)
}
internal func ==(left: ConstraintAttributes, right: ConstraintAttributes) -> Bool {
return left.rawValue == right.rawValue
}
================================================
FILE: shoppingCart/Classes/Library/SnapKit/ConstraintDescription.swift
================================================
//
// SnapKit
//
// Copyright (c) 2011-2015 SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
public protocol RelationTarget {
var constraintItem: ConstraintItem { get }
}
public protocol FloatConvertible: RelationTarget {
var floatValue: Float { get }
}
extension FloatConvertible {
public var constraintItem: ConstraintItem {
return ConstraintItem(object: nil, attributes: ConstraintAttributes.None)
}
}
extension Float: FloatConvertible, RelationTarget {
public var floatValue: Float {
return self
}
}
extension Int: FloatConvertible, RelationTarget {
public var floatValue: Float {
return Float(self)
}
}
extension UInt: FloatConvertible, RelationTarget {
public var floatValue: Float {
return Float(self)
}
}
extension Double: FloatConvertible, RelationTarget {
public var floatValue: Float {
return Float(self)
}
}
extension CGFloat: FloatConvertible, RelationTarget {
public var floatValue: Float {
return Float(self)
}
}
@available(iOS 9.0, OSX 10.11, *)
extension NSLayoutAnchor: RelationTarget {
public var constraintItem: ConstraintItem {
return ConstraintItem(object: self, attributes: ConstraintAttributes.None)
}
}
extension CGPoint: RelationTarget {
public var constraintItem: ConstraintItem {
return ConstraintItem(object: nil, attributes: ConstraintAttributes.None)
}
}
extension CGSize: RelationTarget {
public var constraintItem: ConstraintItem {
return ConstraintItem(object: nil, attributes: ConstraintAttributes.None)
}
}
extension EdgeInsets: RelationTarget {
public var constraintItem: ConstraintItem {
return ConstraintItem(object: nil, attributes: ConstraintAttributes.None)
}
}
extension View: RelationTarget {
public var constraintItem: ConstraintItem {
return ConstraintItem(object: self, attributes: ConstraintAttributes.None)
}
}
extension ConstraintItem: RelationTarget {
public var constraintItem: ConstraintItem {
return self
}
}
/**
Used to expose the final API of a `ConstraintDescription` which allows getting a constraint from it
*/
public class ConstraintDescriptionFinalizable {
private let backing: ConstraintDescription
internal init(_ backing: ConstraintDescription) {
self.backing = backing
}
public var constraint: Constraint {
return backing.constraint
}
}
/**
Used to expose priority APIs
*/
public class ConstraintDescriptionPriortizable: ConstraintDescriptionFinalizable {
public func priority(priority: FloatConvertible) -> ConstraintDescriptionFinalizable {
return ConstraintDescriptionFinalizable(self.backing.priority(priority))
}
public func priorityRequired() -> ConstraintDescriptionFinalizable {
return ConstraintDescriptionFinalizable(self.backing.priorityRequired())
}
public func priorityHigh() -> ConstraintDescriptionFinalizable {
return ConstraintDescriptionFinalizable(self.backing.priorityHigh())
}
public func priorityMedium() -> ConstraintDescriptionFinalizable {
return ConstraintDescriptionFinalizable(self.backing.priorityMedium())
}
public func priorityLow() -> ConstraintDescriptionFinalizable {
return ConstraintDescriptionFinalizable(self.backing.priorityLow())
}
}
/**
Used to expose multiplier & constant APIs
*/
public class ConstraintDescriptionEditable: ConstraintDescriptionPriortizable {
public func multipliedBy(amount: FloatConvertible) -> ConstraintDescriptionEditable {
return ConstraintDescriptionEditable(self.backing.multipliedBy(amount))
}
public func dividedBy(amount: FloatConvertible) -> ConstraintDescriptionEditable {
return self.multipliedBy(1 / amount.floatValue)
}
public func offset(amount: FloatConvertible) -> ConstraintDescriptionEditable {
return ConstraintDescriptionEditable(self.backing.offset(amount))
}
public func offset(amount: CGPoint) -> ConstraintDescriptionEditable {
return ConstraintDescriptionEditable(self.backing.offset(amount))
}
public func offset(amount: CGSize) -> ConstraintDescriptionEditable {
return ConstraintDescriptionEditable(self.backing.offset(amount))
}
public func offset(amount: EdgeInsets) -> ConstraintDescriptionEditable {
return ConstraintDescriptionEditable(self.backing.offset(amount))
}
public func inset(amount: FloatConvertible) -> ConstraintDescriptionEditable {
return ConstraintDescriptionEditable(self.backing.inset(amount))
}
public func inset(amount: EdgeInsets) -> ConstraintDescriptionEditable {
return ConstraintDescriptionEditable(self.backing.inset(amount))
}
}
/**
Used to expose relation APIs
*/
public class ConstraintDescriptionRelatable {
private let backing: ConstraintDescription
init(_ backing: ConstraintDescription) {
self.backing = backing
}
public func equalTo(other: RelationTarget, file: String = __FILE__, line: UInt = __LINE__) -> ConstraintDescriptionEditable {
let location = SourceLocation(file: file, line: line)
return ConstraintDescriptionEditable(self.backing.constrainTo(other, relation: .Equal, location: location))
}
public func equalTo(other: LayoutSupport, file: String = __FILE__, line: UInt = __LINE__) -> ConstraintDescriptionEditable {
let location = SourceLocation(file: file, line: line)
return ConstraintDescriptionEditable(self.backing.constrainTo(other, relation: .Equal, location: location))
}
public func lessThanOrEqualTo(other: RelationTarget, file: String = __FILE__, line: UInt = __LINE__) -> ConstraintDescriptionEditable {
let location = SourceLocation(file: file, line: line)
return ConstraintDescriptionEditable(self.backing.constrainTo(other, relation: .LessThanOrEqualTo, location: location))
}
public func lessThanOrEqualTo(other: LayoutSupport, file: String = __FILE__, line: UInt = __LINE__) -> ConstraintDescriptionEditable {
let location = SourceLocation(file: file, line: line)
return ConstraintDescriptionEditable(self.backing.constrainTo(other, relation: .LessThanOrEqualTo, location: location))
}
public func greaterThanOrEqualTo(other: RelationTarget, file: String = __FILE__, line: UInt = __LINE__) -> ConstraintDescriptionEditable {
let location = SourceLocation(file: file, line: line)
return ConstraintDescriptionEditable(self.backing.constrainTo(other, relation: .GreaterThanOrEqualTo, location: location))
}
public func greaterThanOrEqualTo(other: LayoutSupport, file: String = __FILE__, line: UInt = __LINE__) -> ConstraintDescriptionEditable {
let location = SourceLocation(file: file, line: line)
return ConstraintDescriptionEditable(self.backing.constrainTo(other, relation: .GreaterThanOrEqualTo, location: location))
}
}
/**
Used to expose chaining APIs
*/
public class ConstraintDescriptionExtendable: ConstraintDescriptionRelatable {
public var left: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.left)
}
public var top: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.top)
}
public var bottom: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.bottom)
}
public var right: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.right)
}
public var leading: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.leading)
}
public var trailing: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.trailing)
}
public var width: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.width)
}
public var height: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.height)
}
public var centerX: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.centerX)
}
public var centerY: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.centerY)
}
public var baseline: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.baseline)
}
@available(iOS 8.0, *)
public var firstBaseline: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.firstBaseline)
}
@available(iOS 8.0, *)
public var leftMargin: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.leftMargin)
}
@available(iOS 8.0, *)
public var rightMargin: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.rightMargin)
}
@available(iOS 8.0, *)
public var topMargin: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.topMargin)
}
@available(iOS 8.0, *)
public var bottomMargin: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.bottomMargin)
}
@available(iOS 8.0, *)
public var leadingMargin: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.leadingMargin)
}
@available(iOS 8.0, *)
public var trailingMargin: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.trailingMargin)
}
@available(iOS 8.0, *)
public var centerXWithinMargins: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.centerXWithinMargins)
}
@available(iOS 8.0, *)
public var centerYWithinMargins: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.centerYWithinMargins)
}
}
/**
Used to internally manage building constraint
*/
internal class ConstraintDescription {
private var location: SourceLocation? = nil
private var left: ConstraintDescription { return self.addConstraint(ConstraintAttributes.Left) }
private var top: ConstraintDescription { return self.addConstraint(ConstraintAttributes.Top) }
private var right: ConstraintDescription { return self.addConstraint(ConstraintAttributes.Right) }
private var bottom: ConstraintDescription { return self.addConstraint(ConstraintAttributes.Bottom) }
private var leading: ConstraintDescription { return self.addConstraint(ConstraintAttributes.Leading) }
private var trailing: ConstraintDescription { return self.addConstraint(ConstraintAttributes.Trailing) }
private var width: ConstraintDescription { return self.addConstraint(ConstraintAttributes.Width) }
private var height: ConstraintDescription { return self.addConstraint(ConstraintAttributes.Height) }
private var centerX: ConstraintDescription { return self.addConstraint(ConstraintAttributes.CenterX) }
private var centerY: ConstraintDescription { return self.addConstraint(ConstraintAttributes.CenterY) }
private var baseline: ConstraintDescription { return self.addConstraint(ConstraintAttributes.Baseline) }
@available(iOS 8.0, *)
private var firstBaseline: ConstraintDescription { return self.addConstraint(ConstraintAttributes.FirstBaseline) }
@available(iOS 8.0, *)
private var leftMargin: ConstraintDescription { return self.addConstraint(ConstraintAttributes.LeftMargin) }
@available(iOS 8.0, *)
private var rightMargin: ConstraintDescription { return self.addConstraint(ConstraintAttributes.RightMargin) }
@available(iOS 8.0, *)
private var topMargin: ConstraintDescription { return self.addConstraint(ConstraintAttributes.TopMargin) }
@available(iOS 8.0, *)
private var bottomMargin: ConstraintDescription { return self.addConstraint(ConstraintAttributes.BottomMargin) }
@available(iOS 8.0, *)
private var leadingMargin: ConstraintDescription { return self.addConstraint(ConstraintAttributes.LeadingMargin) }
@available(iOS 8.0, *)
private var trailingMargin: ConstraintDescription { return self.addConstraint(ConstraintAttributes.TrailingMargin) }
@available(iOS 8.0, *)
private var centerXWithinMargins: ConstraintDescription { return self.addConstraint(ConstraintAttributes.CenterXWithinMargins) }
@available(iOS 8.0, *)
private var centerYWithinMargins: ConstraintDescription { return self.addConstraint(ConstraintAttributes.CenterYWithinMargins) }
// MARK: initializer
init(fromItem: ConstraintItem) {
self.fromItem = fromItem
self.toItem = ConstraintItem(object: nil, attributes: ConstraintAttributes.None)
}
// MARK: multiplier
private func multipliedBy(amount: FloatConvertible) -> ConstraintDescription {
self.multiplier = amount.floatValue
return self
}
private func dividedBy(amount: FloatConvertible) -> ConstraintDescription {
self.multiplier = 1.0 / amount.floatValue;
return self
}
// MARK: offset
private func offset(amount: FloatConvertible) -> ConstraintDescription {
self.constant = amount.floatValue
return self
}
private func offset(amount: CGPoint) -> ConstraintDescription {
self.constant = amount
return self
}
private func offset(amount: CGSize) -> ConstraintDescription {
self.constant = amount
return self
}
private func offset(amount: EdgeInsets) -> ConstraintDescription {
self.constant = amount
return self
}
// MARK: inset
private func inset(amount: FloatConvertible) -> ConstraintDescription {
let value = CGFloat(amount.floatValue)
self.constant = EdgeInsets(top: value, left: value, bottom: -value, right: -value)
return self
}
private func inset(amount: EdgeInsets) -> ConstraintDescription {
self.constant = EdgeInsets(top: amount.top, left: amount.left, bottom: -amount.bottom, right: -amount.right)
return self
}
// MARK: priority
private func priority(priority: FloatConvertible) -> ConstraintDescription {
self.priority = priority.floatValue
return self
}
private func priorityRequired() -> ConstraintDescription {
return self.priority(1000.0)
}
private func priorityHigh() -> ConstraintDescription {
return self.priority(750.0)
}
private func priorityMedium() -> ConstraintDescription {
#if os(iOS) || os(tvOS)
return self.priority(500.0)
#else
return self.priority(501.0)
#endif
}
private func priorityLow() -> ConstraintDescription {
return self.priority(250.0)
}
// MARK: Constraint
internal var constraint: Constraint {
if self.concreteConstraint == nil {
if self.relation == nil {
fatalError("Attempting to create a constraint from a ConstraintDescription before it has been fully chained.")
}
self.concreteConstraint = ConcreteConstraint(
fromItem: self.fromItem,
toItem: self.toItem,
relation: self.relation!,
constant: self.constant,
multiplier: self.multiplier,
priority: self.priority,
location: self.location
)
}
return self.concreteConstraint!
}
// MARK: Private
private let fromItem: ConstraintItem
private var toItem: ConstraintItem {
willSet {
if self.concreteConstraint != nil {
fatalError("Attempting to modify a ConstraintDescription after its constraint has been created.")
}
}
}
private var relation: ConstraintRelation? {
willSet {
if self.concreteConstraint != nil {
fatalError("Attempting to modify a ConstraintDescription after its constraint has been created.")
}
}
}
private var constant: Any = Float(0.0) {
willSet {
if self.concreteConstraint != nil {
fatalError("Attempting to modify a ConstraintDescription after its constraint has been created.")
}
}
}
private var multiplier: Float = 1.0 {
willSet {
if self.concreteConstraint != nil {
fatalError("Attempting to modify a ConstraintDescription after its constraint has been created.")
}
}
}
private var priority: Float = 1000.0 {
willSet {
if self.concreteConstraint != nil {
fatalError("Attempting to modify a ConstraintDescription after its constraint has been created.")
}
}
}
private var concreteConstraint: ConcreteConstraint? = nil
private func addConstraint(attributes: ConstraintAttributes) -> ConstraintDescription {
if self.relation == nil {
self.fromItem.attributes += attributes
}
return self
}
private func constrainTo(other: RelationTarget, relation: ConstraintRelation, location: SourceLocation) -> ConstraintDescription {
self.location = location
if let constant = other as? FloatConvertible {
self.constant = constant.floatValue
}
let item = other.constraintItem
if item.attributes != ConstraintAttributes.None {
let toLayoutAttributes = item.attributes.layoutAttributes
if toLayoutAttributes.count > 1 {
let fromLayoutAttributes = self.fromItem.attributes.layoutAttributes
if toLayoutAttributes != fromLayoutAttributes {
NSException(name: "Invalid Constraint", reason: "Cannot constrain to multiple non identical attributes", userInfo: nil).raise()
return self
}
item.attributes = ConstraintAttributes.None
}
}
self.toItem = item
self.relation = relation
return self
}
@available(iOS 7.0, *)
private func constrainTo(other: LayoutSupport, relation: ConstraintRelation, location: SourceLocation) -> ConstraintDescription {
return constrainTo(ConstraintItem(object: other, attributes: ConstraintAttributes.None), relation: relation, location: location)
}
}
================================================
FILE: shoppingCart/Classes/Library/SnapKit/ConstraintItem.swift
================================================
//
// SnapKit
//
// Copyright (c) 2011-2015 SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
/**
Used to assist in building a constraint
*/
public class ConstraintItem {
internal init(object: AnyObject?, attributes: ConstraintAttributes) {
self.object = object
self.attributes = attributes
}
internal weak var object: AnyObject?
internal var attributes: ConstraintAttributes
internal var view: View? {
return self.object as? View
}
@available(iOS 7.0, *)
internal var layoutSupport: LayoutSupport? {
return self.object as? LayoutSupport
}
}
internal func ==(left: ConstraintItem, right: ConstraintItem) -> Bool {
if left.object == nil {
return false
}
if right.object == nil {
return false
}
if left.object !== right.object {
return false
}
if left.attributes != right.attributes {
return false
}
return true
}
================================================
FILE: shoppingCart/Classes/Library/SnapKit/ConstraintMaker.swift
================================================
//
// SnapKit
//
// Copyright (c) 2011-2015 SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
/**
Used to make constraints
*/
public class ConstraintMaker {
/// left edge
public var left: ConstraintDescriptionExtendable { return self.makeConstraintDescription(ConstraintAttributes.Left) }
/// top edge
public var top: ConstraintDescriptionExtendable { return self.makeConstraintDescription(ConstraintAttributes.Top) }
/// right edge
public var right: ConstraintDescriptionExtendable { return self.makeConstraintDescription(ConstraintAttributes.Right) }
/// bottom edge
public var bottom: ConstraintDescriptionExtendable { return self.makeConstraintDescription(ConstraintAttributes.Bottom) }
/// leading edge
public var leading: ConstraintDescriptionExtendable { return self.makeConstraintDescription(ConstraintAttributes.Leading) }
/// trailing edge
public var trailing: ConstraintDescriptionExtendable { return self.makeConstraintDescription(ConstraintAttributes.Trailing) }
/// width dimension
public var width: ConstraintDescriptionExtendable { return self.makeConstraintDescription(ConstraintAttributes.Width) }
/// height dimension
public var height: ConstraintDescriptionExtendable { return self.makeConstraintDescription(ConstraintAttributes.Height) }
/// centerX dimension
public var centerX: ConstraintDescriptionExtendable { return self.makeConstraintDescription(ConstraintAttributes.CenterX) }
/// centerY dimension
public var centerY: ConstraintDescriptionExtendable { return self.makeConstraintDescription(ConstraintAttributes.CenterY) }
/// baseline position
public var baseline: ConstraintDescriptionExtendable { return self.makeConstraintDescription(ConstraintAttributes.Baseline) }
/// firse baseline position
@available(iOS 8.0, *)
public var firstBaseline: ConstraintDescriptionExtendable { return self.makeConstraintDescription(ConstraintAttributes.FirstBaseline) }
/// left margin
@available(iOS 8.0, *)
public var leftMargin: ConstraintDescriptionExtendable { return self.makeConstraintDescription(ConstraintAttributes.LeftMargin) }
/// right margin
@available(iOS 8.0, *)
public var rightMargin: ConstraintDescriptionExtendable { return self.makeConstraintDescription(ConstraintAttributes.RightMargin) }
/// top margin
@available(iOS 8.0, *)
public var topMargin: ConstraintDescriptionExtendable { return self.makeConstraintDescription(ConstraintAttributes.TopMargin) }
/// bottom margin
@available(iOS 8.0, *)
public var bottomMargin: ConstraintDescriptionExtendable { return self.makeConstraintDescription(ConstraintAttributes.BottomMargin) }
/// leading margin
@available(iOS 8.0, *)
public var leadingMargin: ConstraintDescriptionExtendable { return self.makeConstraintDescription(ConstraintAttributes.LeadingMargin) }
/// trailing margin
@available(iOS 8.0, *)
public var trailingMargin: ConstraintDescriptionExtendable { return self.makeConstraintDescription(ConstraintAttributes.TrailingMargin) }
/// centerX within margins
@available(iOS 8.0, *)
public var centerXWithinMargins: ConstraintDescriptionExtendable { return self.makeConstraintDescription(ConstraintAttributes.CenterXWithinMargins) }
/// centerY within margins
@available(iOS 8.0, *)
public var centerYWithinMargins: ConstraintDescriptionExtendable { return self.makeConstraintDescription(ConstraintAttributes.CenterYWithinMargins) }
/// top + left + bottom + right edges
public var edges: ConstraintDescriptionExtendable { return self.makeConstraintDescription(ConstraintAttributes.Edges) }
/// width + height dimensions
public var size: ConstraintDescriptionExtendable { return self.makeConstraintDescription(ConstraintAttributes.Size) }
// centerX + centerY positions
public var center: ConstraintDescriptionExtendable { return self.makeConstraintDescription(ConstraintAttributes.Center) }
// top + left + bottom + right margins
@available(iOS 8.0, *)
public var margins: ConstraintDescriptionExtendable { return self.makeConstraintDescription(ConstraintAttributes.Margins) }
// centerX + centerY within margins
@available(iOS 8.0, *)
public var centerWithinMargins: ConstraintDescriptionExtendable { return self.makeConstraintDescription(ConstraintAttributes.CenterWithinMargins) }
internal init(view: View, location: SourceLocation) {
self.view = view
self.location = location
}
internal let location: SourceLocation
internal let view: View
internal var constraintDescriptions = [ConstraintDescription]()
internal func makeConstraintDescription(attributes: ConstraintAttributes) -> ConstraintDescriptionExtendable {
let item = ConstraintItem(object: self.view, attributes: attributes)
let constraintDescription = ConstraintDescription(fromItem: item)
self.constraintDescriptions.append(constraintDescription)
return ConstraintDescriptionExtendable(constraintDescription)
}
internal class func prepareConstraints(view view: View, location: SourceLocation, @noescape closure: (make: ConstraintMaker) -> Void) -> [Constraint] {
let maker = ConstraintMaker(view: view, location: location)
closure(make: maker)
let constraints = maker.constraintDescriptions.map { $0.constraint }
for constraint in constraints {
constraint.makerLocation = maker.location
}
return constraints
}
internal class func makeConstraints(view view: View, location: SourceLocation, @noescape closure: (make: ConstraintMaker) -> Void) {
view.translatesAutoresizingMaskIntoConstraints = false
let maker = ConstraintMaker(view: view, location: location)
closure(make: maker)
let constraints = maker.constraintDescriptions.map { $0.constraint as! ConcreteConstraint }
for constraint in constraints {
constraint.makerLocation = maker.location
constraint.installOnView(updateExisting: false)
}
}
internal class func remakeConstraints(view view: View, location: SourceLocation, @noescape closure: (make: ConstraintMaker) -> Void) {
view.translatesAutoresizingMaskIntoConstraints = false
let maker = ConstraintMaker(view: view, location: location)
closure(make: maker)
self.removeConstraints(view: view)
let constraints = maker.constraintDescriptions.map { $0.constraint as! ConcreteConstraint }
for constraint in constraints {
constraint.makerLocation = maker.location
constraint.installOnView(updateExisting: false)
}
}
internal class func updateConstraints(view view: View, location: SourceLocation, @noescape closure: (make: ConstraintMaker) -> Void) {
view.translatesAutoresizingMaskIntoConstraints = false
let maker = ConstraintMaker(view: view, location: location)
closure(make: maker)
let constraints = maker.constraintDescriptions.map { $0.constraint as! ConcreteConstraint}
for constraint in constraints {
constraint.makerLocation = maker.location
constraint.installOnView(updateExisting: true)
}
}
internal class func removeConstraints(view view: View) {
for existingLayoutConstraint in view.snp_installedLayoutConstraints {
existingLayoutConstraint.snp_constraint?.uninstall()
}
}
}
================================================
FILE: shoppingCart/Classes/Library/SnapKit/ConstraintRelation.swift
================================================
//
// SnapKit
//
// Copyright (c) 2011-2015 SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
/**
Used to define `NSLayoutRelation`
*/
internal enum ConstraintRelation: Int {
case Equal = 1, LessThanOrEqualTo, GreaterThanOrEqualTo
internal var layoutRelation: NSLayoutRelation {
get {
switch(self) {
case .LessThanOrEqualTo:
return .LessThanOrEqual
case .GreaterThanOrEqualTo:
return .GreaterThanOrEqual
default:
return .Equal
}
}
}
}
================================================
FILE: shoppingCart/Classes/Library/SnapKit/Debugging.swift
================================================
//
// SnapKit
//
// Copyright (c) 2011-2015 SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
/**
Used to allow adding a snp_label to a View for debugging purposes
*/
public extension View {
public var snp_label: String? {
get {
return objc_getAssociatedObject(self, &labelKey) as? String
}
set {
objc_setAssociatedObject(self, &labelKey, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_COPY_NONATOMIC)
}
}
}
/**
Used to allow adding a snp_label to a LayoutConstraint for debugging purposes
*/
public extension LayoutConstraint {
public var snp_label: String? {
get {
return objc_getAssociatedObject(self, &labelKey) as? String
}
set {
objc_setAssociatedObject(self, &labelKey, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_COPY_NONATOMIC)
}
}
override public var description: String {
var description = "<"
description += descriptionForObject(self)
description += " \(descriptionForObject(self.firstItem))"
if self.firstAttribute != .NotAnAttribute {
description += ".\(self.firstAttribute.snp_description)"
}
description += " \(self.relation.snp_description)"
if let secondItem: AnyObject = self.secondItem {
description += " \(descriptionForObject(secondItem))"
}
if self.secondAttribute != .NotAnAttribute {
description += ".\(self.secondAttribute.snp_description)"
}
if self.multiplier != 1.0 {
description += " * \(self.multiplier)"
}
if self.secondAttribute == .NotAnAttribute {
description += " \(self.constant)"
} else {
if self.constant > 0.0 {
description += " + \(self.constant)"
} else if self.constant < 0.0 {
description += " - \(CGFloat.abs(self.constant))"
}
}
if self.priority != 1000.0 {
description += " ^\(self.priority)"
}
description += ">"
return description
}
internal var snp_makerFile: String? {
return self.snp_constraint?.makerLocation.file
}
internal var snp_makerLine: UInt? {
return self.snp_constraint?.makerLocation.line
}
}
private var labelKey = ""
private func descriptionForObject(object: AnyObject) -> String {
let pointerDescription = NSString(format: "%p", ObjectIdentifier(object).uintValue)
var desc = ""
desc += object.dynamicType.description()
if let object = object as? View {
desc += ":\(object.snp_label ?? pointerDescription)"
} else if let object = object as? LayoutConstraint {
desc += ":\(object.snp_label ?? pointerDescription)"
} else {
desc += ":\(pointerDescription)"
}
if let object = object as? LayoutConstraint, let file = object.snp_makerFile, let line = object.snp_makerLine {
desc += "@\(file)#\(line)"
}
desc += ""
return desc
}
private extension NSLayoutRelation {
private var snp_description: String {
switch self {
case .Equal: return "=="
case .GreaterThanOrEqual: return ">="
case .LessThanOrEqual: return "<="
}
}
}
private extension NSLayoutAttribute {
private var snp_description: String {
#if os(iOS) || os(tvOS)
switch self {
case .NotAnAttribute: return "notAnAttribute"
case .Top: return "top"
case .Left: return "left"
case .Bottom: return "bottom"
case .Right: return "right"
case .Leading: return "leading"
case .Trailing: return "trailing"
case .Width: return "width"
case .Height: return "height"
case .CenterX: return "centerX"
case .CenterY: return "centerY"
case .Baseline: return "baseline"
case .FirstBaseline: return "firstBaseline"
case .TopMargin: return "topMargin"
case .LeftMargin: return "leftMargin"
case .BottomMargin: return "bottomMargin"
case .RightMargin: return "rightMargin"
case .LeadingMargin: return "leadingMargin"
case .TrailingMargin: return "trailingMargin"
case .CenterXWithinMargins: return "centerXWithinMargins"
case .CenterYWithinMargins: return "centerYWithinMargins"
}
#else
switch self {
case .NotAnAttribute: return "notAnAttribute"
case .Top: return "top"
case .Left: return "left"
case .Bottom: return "bottom"
case .Right: return "right"
case .Leading: return "leading"
case .Trailing: return "trailing"
case .Width: return "width"
case .Height: return "height"
case .CenterX: return "centerX"
case .CenterY: return "centerY"
case .Baseline: return "baseline"
default: return "default"
}
#endif
}
}
================================================
FILE: shoppingCart/Classes/Library/SnapKit/EdgeInsets.swift
================================================
//
// SnapKit
//
// Copyright (c) 2011-2015 SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
public typealias EdgeInsets = UIEdgeInsets
public func EdgeInsetsMake(top: CGFloat, left: CGFloat, bottom: CGFloat, right: CGFloat) -> EdgeInsets {
return EdgeInsets(top: top, left: left, bottom: bottom, right: right)
}
public let EdgeInsetsZero = EdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
#else
import AppKit
public typealias EdgeInsets = NSEdgeInsets
public func EdgeInsetsMake(top: CGFloat, left: CGFloat, bottom: CGFloat, right: CGFloat) -> EdgeInsets {
return EdgeInsets(top: top, left: left, bottom: bottom, right: right)
}
public let EdgeInsetsZero = EdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
#endif
================================================
FILE: shoppingCart/Classes/Library/SnapKit/LayoutConstraint.swift
================================================
//
// SnapKit
//
// Copyright (c) 2011-2015 SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
/**
Used to add extra information to the actual `NSLayoutConstraint`'s that will UIKit/AppKit will utilize
*/
public class LayoutConstraint: NSLayoutConstraint {
internal var snp_constraint: Constraint? = nil
public var snp_location: SourceLocation? {
return snp_constraint?.location
}
}
internal func ==(left: LayoutConstraint, right: LayoutConstraint) -> Bool {
if left.firstItem !== right.firstItem {
return false
}
if left.secondItem !== right.secondItem {
return false
}
if left.firstAttribute != right.firstAttribute {
return false
}
if left.secondAttribute != right.secondAttribute {
return false
}
if left.relation != right.relation {
return false
}
if left.priority != right.priority {
return false
}
if left.multiplier != right.multiplier {
return false
}
return true
}
================================================
FILE: shoppingCart/Classes/Library/SnapKit/SnapKit.h
================================================
//
// SnapKit
//
// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import <Foundation/Foundation.h>
FOUNDATION_EXPORT double SnapKitVersionNumber;
FOUNDATION_EXPORT const unsigned char SnapKitVersionString[];
================================================
FILE: shoppingCart/Classes/Library/SnapKit/SnapKit.swift
================================================
//
// SnapKit
//
// Copyright (c) 2011-2015 SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
public typealias InterfaceLayoutDirection = UIUserInterfaceLayoutDirection
public typealias LayoutSupport = UILayoutSupport
#else
import AppKit
public typealias InterfaceLayoutDirection = NSUserInterfaceLayoutDirection
public class LayoutSupport {}
#endif
/**
Used to configure different parts of SnapKit
*/
public struct Config {
/// The interface layout direction
public static var interfaceLayoutDirection = InterfaceLayoutDirection.LeftToRight
}
================================================
FILE: shoppingCart/Classes/Library/SnapKit/SourceLocation.swift
================================================
//
// SnapKit
//
// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
public struct SourceLocation {
public let file: String
public let line: UInt
init(file: String, line: UInt) {
self.file = file
self.line = line
}
}
================================================
FILE: shoppingCart/Classes/Library/SnapKit/View+SnapKit.swift
================================================
//
// SnapKit
//
// Copyright (c) 2011-2015 SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
public typealias View = UIView
#else
import AppKit
public typealias View = NSView
#endif
/**
Used to expose public API on views
*/
public extension View {
/// left edge
public var snp_left: ConstraintItem { return ConstraintItem(object: self, attributes: ConstraintAttributes.Left) }
/// top edge
public var snp_top: ConstraintItem { return ConstraintItem(object: self, attributes: ConstraintAttributes.Top) }
/// right edge
public var snp_right: ConstraintItem { return ConstraintItem(object: self, attributes: ConstraintAttributes.Right) }
/// bottom edge
public var snp_bottom: ConstraintItem { return ConstraintItem(object: self, attributes: ConstraintAttributes.Bottom) }
/// leading edge
public var snp_leading: ConstraintItem { return ConstraintItem(object: self, attributes: ConstraintAttributes.Leading) }
/// trailing edge
public var snp_trailing: ConstraintItem { return ConstraintItem(object: self, attributes: ConstraintAttributes.Trailing) }
/// width dimension
public var snp_width: ConstraintItem { return ConstraintItem(object: self, attributes: ConstraintAttributes.Width) }
/// height dimension
public var snp_height: ConstraintItem { return ConstraintItem(object: self, attributes: ConstraintAttributes.Height) }
/// centerX position
public var snp_centerX: ConstraintItem { return ConstraintItem(object: self, attributes: ConstraintAttributes.CenterX) }
/// centerY position
public var snp_centerY: ConstraintItem { return ConstraintItem(object: self, attributes: ConstraintAttributes.CenterY) }
/// baseline position
public var snp_baseline: ConstraintItem { return ConstraintItem(object: self, attributes: ConstraintAttributes.Baseline) }
/// first baseline position
@available(iOS 8.0, *)
public var snp_firstBaseline: ConstraintItem { return ConstraintItem(object: self, attributes: ConstraintAttributes.FirstBaseline) }
/// left margin
@available(iOS 8.0, *)
public var snp_leftMargin: ConstraintItem { return ConstraintItem(object: self, attributes: ConstraintAttributes.LeftMargin) }
/// right margin
@available(iOS 8.0, *)
public var snp_rightMargin: ConstraintItem { return ConstraintItem(object: self, attributes: ConstraintAttributes.RightMargin) }
/// top margin
@available(iOS 8.0, *)
public var snp_topMargin: ConstraintItem { return ConstraintItem(object: self, attributes: ConstraintAttributes.TopMargin) }
/// bottom margin
@available(iOS 8.0, *)
public var snp_bottomMargin: ConstraintItem { return ConstraintItem(object: self, attributes: ConstraintAttributes.BottomMargin) }
/// leading margin
@available(iOS 8.0, *)
public var snp_leadingMargin: ConstraintItem { return ConstraintItem(object: self, attributes: ConstraintAttributes.LeadingMargin) }
/// trailing margin
@available(iOS 8.0, *)
public var snp_trailingMargin: ConstraintItem { return ConstraintItem(object: self, attributes: ConstraintAttributes.TrailingMargin) }
/// centerX within margins
@available(iOS 8.0, *)
public var snp_centerXWithinMargins: ConstraintItem { return ConstraintItem(object: self, attributes: ConstraintAttributes.CenterXWithinMargins) }
/// centerY within margins
@available(iOS 8.0, *)
public var snp_centerYWithinMargins: ConstraintItem { return ConstraintItem(object: self, attributes: ConstraintAttributes.CenterYWithinMargins) }
// top + left + bottom + right edges
public var snp_edges: ConstraintItem { return ConstraintItem(object: self, attributes: ConstraintAttributes.Edges) }
// width + height dimensions
public var snp_size: ConstraintItem { return ConstraintItem(object: self, attributes: ConstraintAttributes.Size) }
// centerX + centerY positions
public var snp_center: ConstraintItem { return ConstraintItem(object: self, attributes: ConstraintAttributes.Center) }
// top + left + bottom + right margins
@available(iOS 8.0, *)
public var snp_margins: ConstraintItem { return ConstraintItem(object: self, attributes: ConstraintAttributes.Margins) }
// centerX + centerY within margins
@available(iOS 8.0, *)
public var snp_centerWithinMargins: ConstraintItem { return ConstraintItem(object: self, attributes: ConstraintAttributes.CenterWithinMargins) }
/**
Prepares constraints with a `ConstraintMaker` and returns the made constraints but does not install them.
:param: closure that will be passed the `ConstraintMaker` to make the constraints with
:returns: the constraints made
*/
public func snp_prepareConstraints(file: String = __FILE__, line: UInt = __LINE__, @noescape closure: (make: ConstraintMaker) -> Void) -> [Constraint] {
return ConstraintMaker.prepareConstraints(view: self, location: SourceLocation(file: file, line: line), closure: closure)
}
/**
Makes constraints with a `ConstraintMaker` and installs them along side any previous made constraints.
:param: closure that will be passed the `ConstraintMaker` to make the constraints with
*/
public func snp_makeConstraints(file: String = __FILE__, line: UInt = __LINE__, @noescape closure: (make: ConstraintMaker) -> Void) -> Void {
ConstraintMaker.makeConstraints(view: self, location: SourceLocation(file: file, line: line), closure: closure)
}
/**
Updates constraints with a `ConstraintMaker` that will replace existing constraints that match and install new ones.
For constraints to match only the constant can be updated.
:param: closure that will be passed the `ConstraintMaker` to update the constraints with
*/
public func snp_updateConstraints(file: String = __FILE__, line: UInt = __LINE__, @noescape closure: (make: ConstraintMaker) -> Void) -> Void {
ConstraintMaker.updateConstraints(view: self, location: SourceLocation(file: file, line: line), closure: closure)
}
/**
Remakes constraints with a `ConstraintMaker` that will first remove all previously made constraints and make and install new ones.
:param: closure that will be passed the `ConstraintMaker` to remake the constraints with
*/
public func snp_remakeConstraints(file: String = __FILE__, line: UInt = __LINE__, @noescape closure: (make: ConstraintMaker) -> Void) -> Void {
ConstraintMaker.remakeConstraints(view: self, location: SourceLocation(file: file, line: line), closure: closure)
}
/**
Removes all previously made constraints.
*/
public func snp_removeConstraints() {
ConstraintMaker.removeConstraints(view: self)
}
internal var snp_installedLayoutConstraints: [LayoutConstraint] {
get {
if let constraints = objc_getAssociatedObject(self, &installedLayoutConstraintsKey) as? [LayoutConstraint] {
return constraints
}
return []
}
set {
objc_setAssociatedObject(self, &installedLayoutConstraintsKey, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
private var installedLayoutConstraintsKey = ""
================================================
FILE: shoppingCart/Classes/Library/SnapKit/ViewController+SnapKit.swift
================================================
//
// SnapKit
//
// Copyright (c) 2011-2015 SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
/**
Used to expose public API on view controllers
*/
public extension UIViewController {
/// top layout guide top
public var snp_topLayoutGuideTop: ConstraintItem { return ConstraintItem(object: self.topLayoutGuide, attributes: ConstraintAttributes.Top) }
/// top layout guide bottom
public var snp_topLayoutGuideBottom: ConstraintItem { return ConstraintItem(object: self.topLayoutGuide, attributes: ConstraintAttributes.Bottom) }
/// bottom layout guide top
public var snp_bottomLayoutGuideTop: ConstraintItem { return ConstraintItem(object: self.bottomLayoutGuide, attributes: ConstraintAttributes.Top) }
/// bottom layout guide bottom
public var snp_bottomLayoutGuideBottom: ConstraintItem { return ConstraintItem(object: self.bottomLayoutGuide, attributes: ConstraintAttributes.Bottom) }
}
#endif
================================================
FILE: shoppingCart/Classes/Model/JFGoodModel.swift
================================================
//
// JFGoodModel.swift
// shoppingCart
//
// Created by jianfeng on 15/11/17.
// Copyright © 2015年 六阿哥. All rights reserved.
//
import UIKit
class JFGoodModel: NSObject {
// 是否已经加入购物车
var alreadyAddShoppingCart: Bool = false
// 商品图片名称
var iconName: String?
// 商品标题
var title: String?
// 商品描述
var desc: String?
// 商品购买个数,默认0
var count: Int = 1
// 新价格
var newPrice: String?
// 老价格
var oldPrice: String?
// 是否选中,默认没有选中
var selected: Bool = true
// 字典转模型
init(dict: [String : AnyObject]) {
super.init()
// 使用kvo为当前对象属性设置值
setValuesForKeysWithDictionary(dict)
}
// 防止对象属性和kvc时的dict的key不匹配而崩溃
override func setValue(value: AnyObject?, forUndefinedKey key: String) {}
}
================================================
FILE: shoppingCart/Classes/ShopCart/Controller/JFShoppingCartViewController.swift
================================================
//
// JFShoppingCartViewController.swift
// shoppingCart
//
// Created by jianfeng on 15/11/17.
// Copyright © 2015年 六阿哥. All rights reserved.
//
import UIKit
class JFShoppingCartViewController: UIViewController {
// MARK: - 属性
/// 已经添加进购物车的商品模型数组,初始化
var addGoodArray: [JFGoodModel]? {
didSet {
}
}
/// 总金额,默认0.00
var price: CFloat = 0.00
/// 商品列表cell的重用标识符
private let shoppingCarCellIdentifier = "shoppingCarCell"
// MARK: - view生命周期
override func viewDidLoad() {
super.viewDidLoad()
// 准备UI
prepareUI()
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
// 布局UI
layoutUI()
// 重新计算价格
reCalculateGoodCount()
}
/**
准备UI
*/
private func prepareUI() {
// 标题
navigationItem.title = "购物车列表"
// 导航栏左边返回
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "返回", style: UIBarButtonItemStyle.Plain, target: self, action: "didTappedBackButton")
// view背景颜色
view.backgroundColor = UIColor.whiteColor()
// cell行高
tableView.rowHeight = 80
// 注册cell
tableView.registerClass(JFShoppingCartCell.self, forCellReuseIdentifier: shoppingCarCellIdentifier)
// 添加子控件
view.addSubview(tableView)
view.addSubview(bottomView)
bottomView.addSubview(selectButton)
bottomView.addSubview(totalPriceLabel)
bottomView.addSubview(buyButton)
// 判断是否需要全选
for model in addGoodArray! {
if model.selected != true {
// 只要有一个不等于就不全选
selectButton.selected = false
break
}
}
}
/**
布局UI
*/
private func layoutUI() {
// 约束子控件
tableView.snp_makeConstraints { (make) -> Void in
make.left.top.right.equalTo(0)
make.bottom.equalTo(-49)
}
bottomView.snp_makeConstraints { (make) -> Void in
make.left.bottom.right.equalTo(0)
make.height.equalTo(49)
}
selectButton.snp_makeConstraints { (make) -> Void in
make.left.equalTo(12)
make.centerY.equalTo(bottomView.snp_centerY)
}
totalPriceLabel.snp_makeConstraints { (make) -> Void in
make.center.equalTo(bottomView.snp_center)
}
buyButton.snp_makeConstraints { (make) -> Void in
make.right.equalTo(-12)
make.top.equalTo(9)
make.width.equalTo(88)
make.height.equalTo(30)
}
}
// MARK: - 懒加载
/// tableView
lazy var tableView: UITableView = {
let tableView = UITableView()
// 指定数据源和代理
tableView.dataSource = self
tableView.delegate = self
return tableView
}()
/// 底部视图
lazy var bottomView: UIView = {
let bottomView = UIView()
bottomView.backgroundColor = UIColor.whiteColor()
return bottomView
}()
/// 底部多选、反选按钮
lazy var selectButton: UIButton = {
let selectButton = UIButton(type: UIButtonType.Custom)
selectButton.setImage(UIImage(named: "check_n"), forState: UIControlState.Normal)
selectButton.setImage(UIImage(named: "check_y"), forState: UIControlState.Selected)
selectButton.setTitle("多选\\反选", forState: UIControlState.Normal)
selectButton.setTitleColor(UIColor.grayColor(), forState: UIControlState.Normal)
selectButton.titleLabel?.font = UIFont.systemFontOfSize(12)
selectButton.addTarget(self, action: "didTappedSelectButton:", forControlEvents: UIControlEvents.TouchUpInside)
selectButton.selected = true
selectButton.sizeToFit()
return selectButton
}()
/// 底部总价Label
lazy var totalPriceLabel: UILabel = {
let totalPriceLabel = UILabel()
let attributeText = NSMutableAttributedString(string: "总共价格:\(self.price)0")
attributeText.setAttributes([NSForegroundColorAttributeName : UIColor.redColor()], range: NSMakeRange(5, attributeText.length - 5))
totalPriceLabel.attributedText = attributeText
totalPriceLabel.sizeToFit()
return totalPriceLabel
}()
/// 底部付款按钮
lazy var buyButton: UIButton = {
let buyButton = UIButton(type: UIButtonType.Custom)
buyButton.setTitle("付款", forState: UIControlState.Normal)
buyButton.setBackgroundImage(UIImage(named: "button_cart_add"), forState: UIControlState.Normal)
buyButton.layer.cornerRadius = 15
buyButton.layer.masksToBounds = true
return buyButton
}()
}
// MARK: - UITableViewDataSource, UITableViewDelegate数据、代理
extension JFShoppingCartViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return addGoodArray?.count ?? 0
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// 从缓存池创建cell,不成功就根据重用标识符和注册的cell新创建一个
let cell = tableView.dequeueReusableCellWithIdentifier(shoppingCarCellIdentifier, forIndexPath: indexPath) as! JFShoppingCartCell
// cell取消选中效果
cell.selectionStyle = UITableViewCellSelectionStyle.None
// 指定代理对象
cell.delegate = self
// 传递模型
cell.goodModel = addGoodArray?[indexPath.row]
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
reCalculateGoodCount()
}
}
// MARK: - view上的一些事件处理
extension JFShoppingCartViewController {
/**
返回按钮
*/
@objc private func didTappedBackButton() {
dismissViewControllerAnimated(true, completion: nil)
}
/**
重新计算商品数量
*/
private func reCalculateGoodCount() {
// 遍历模型
for model in addGoodArray! {
// 只计算选中的商品
if model.selected == true {
price += Float(model.count) * (model.newPrice! as NSString).floatValue
}
}
// 赋值价格
let attributeText = NSMutableAttributedString(string: "总共价格:\(self.price)0")
attributeText.setAttributes([NSForegroundColorAttributeName : UIColor.redColor()], range: NSMakeRange(5, attributeText.length - 5))
totalPriceLabel.attributedText = attributeText
// 清空price
price = 0
// 刷新表格
tableView.reloadData()
}
/**
点击了多选按钮后的事件处理
- parameter button: 多选按钮
*/
@objc private func didTappedSelectButton(button: UIButton) {
selectButton.selected = !selectButton.selected
for model in addGoodArray! {
model.selected = selectButton.selected
}
// 重新计算总价
reCalculateGoodCount()
// 刷新表格
tableView.reloadData()
}
}
// MARK: - JFShoppingCartCellDelegate代理方法
extension JFShoppingCartViewController: JFShoppingCartCellDelegate {
/**
当点击了cell中加、减按钮
- parameter cell: 被点击的cell
- parameter button: 被点击的按钮
- parameter countLabel: 显示数量的label
*/
func shoppingCartCell(cell: JFShoppingCartCell, button: UIButton, countLabel: UILabel) {
// 根据cell获取当前模型
guard let indexPath = tableView.indexPathForCell(cell) else {
return
}
// 获取当前模型,添加到购物车模型数组
let model = addGoodArray![indexPath.row]
if button.tag == 10 {
if model.count < 1 {
print("数量不能低于0")
return
}
// 减
model.count--
countLabel.text = "\(model.count)"
} else {
// 加
model.count++
countLabel.text = "\(model.count)"
}
// 重新计算商品数量
reCalculateGoodCount()
}
/**
重新计算总价
*/
func reCalculateTotalPrice() {
reCalculateGoodCount()
}
}
================================================
FILE: shoppingCart/Classes/ShopCart/View/JFOldPriceLabel.swift
================================================
//
// JFOldPriceLabel.swift
// shoppingCart
//
// Created by jianfeng on 15/11/18.
// Copyright © 2015年 六阿哥. All rights reserved.
//
import UIKit
class JFOldPriceLabel: UILabel {
override func drawRect(rect: CGRect) {
// 调用父类是为了让Label原有数据正常显示
super.drawRect(rect)
// 绘制中划线
let ctx = UIGraphicsGetCurrentContext()
CGContextMoveToPoint(ctx, 0, rect.size.height * 0.5)
CGContextAddLineToPoint(ctx, rect.size.width, rect.size.height * 0.5)
CGContextStrokePath(ctx)
}
}
================================================
FILE: shoppingCart/Classes/ShopCart/View/JFShoppingCartCell.swift
================================================
//
// JFShoppingCartCell.swift
// shoppingCart
//
// Created by jianfeng on 15/11/18.
// Copyright © 2015年 六阿哥. All rights reserved.
//
import UIKit
protocol JFShoppingCartCellDelegate: NSObjectProtocol {
func shoppingCartCell(cell: JFShoppingCartCell, button: UIButton, countLabel: UILabel)
func reCalculateTotalPrice()
}
class JFShoppingCartCell: UITableViewCell {
// MARK: - 属性
/// 商品模型
var goodModel: JFGoodModel? {
didSet {
// 选中状态
selectButton.selected = goodModel!.selected
goodCountLabel.text = "\(goodModel!.count)"
if let iconName = goodModel?.iconName {
iconView.image = UIImage(named: iconName)
}
if let title = goodModel?.title {
titleLabel.text = title
}
if let newPrice = goodModel?.newPrice {
newPriceLabel.text = newPrice
}
if let oldPrice = goodModel?.oldPrice {
oldPriceLabel.text = oldPrice
}
// 重新布局,会更新frame
layoutIfNeeded()
}
}
/// 代理属性
weak var delegate: JFShoppingCartCellDelegate?
// MARK: - 构造方法
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
// 准备UI
prepareUI()
}
/**
准备UI
*/
private func prepareUI() {
// 添加子控件
contentView.addSubview(selectButton)
contentView.addSubview(iconView)
contentView.addSubview(titleLabel)
contentView.addSubview(newPriceLabel)
contentView.addSubview(oldPriceLabel)
contentView.addSubview(addAndsubtraction)
addAndsubtraction.addSubview(subtractionButton)
addAndsubtraction.addSubview(goodCountLabel)
addAndsubtraction.addSubview(addButton)
// 约束子控件
selectButton.snp_makeConstraints { (make) -> Void in
make.left.equalTo(12)
make.centerY.equalTo(contentView.snp_centerY)
}
iconView.snp_makeConstraints { (make) -> Void in
make.left.equalTo(42)
make.top.equalTo(10)
make.width.equalTo(60)
make.height.equalTo(60)
}
titleLabel.snp_makeConstraints { (make) -> Void in
make.top.equalTo(contentView.snp_top).offset(10)
make.left.equalTo(iconView.snp_right).offset(12)
}
newPriceLabel.snp_makeConstraints { (make) -> Void in
make.top.equalTo(titleLabel.snp_top).offset(5)
make.right.equalTo(-12)
}
oldPriceLabel.snp_makeConstraints { (make) -> Void in
make.top.equalTo(newPriceLabel.snp_bottom).offset(5)
make.right.equalTo(-12)
}
addAndsubtraction.snp_makeConstraints { (make) -> Void in
make.left.equalTo(120)
make.top.equalTo(40)
make.width.equalTo(100)
make.height.equalTo(30)
}
subtractionButton.snp_makeConstraints { (make) -> Void in
make.left.equalTo(0)
make.top.equalTo(0)
make.width.equalTo(30)
make.height.equalTo(30)
}
goodCountLabel.snp_makeConstraints { (make) -> Void in
make.left.equalTo(30)
make.top.equalTo(0)
make.width.equalTo(40)
make.height.equalTo(30)
}
addButton.snp_makeConstraints { (make) -> Void in
make.left.equalTo(70)
make.top.equalTo(0)
make.width.equalTo(30)
make.height.equalTo(30)
}
}
// MARK: - 响应事件
/**
被点击的按钮,tag10 减 tag11 加
- parameter button: 按钮
*/
@objc private func didTappedCalculateButton(button: UIButton) {
delegate?.shoppingCartCell(self, button: button, countLabel: goodCountLabel)
}
/**
选中了按钮后触发
- parameter button: 被选中的按钮
*/
@objc private func didSelectedButton(button: UIButton) {
// 选中
button.selected = !button.selected
goodModel?.selected = button.selected
// 重新计算价格
delegate?.reCalculateTotalPrice()
}
// MARK: - 懒加载
/// 选择按钮
private lazy var selectButton: UIButton = {
let selectButton = UIButton(type: UIButtonType.Custom)
selectButton.setImage(UIImage(named: "check_n"), forState: UIControlState.Normal)
selectButton.setImage(UIImage(named: "check_y"), forState: UIControlState.Selected)
selectButton.addTarget(self, action: "didSelectedButton:", forControlEvents: UIControlEvents.TouchUpInside)
selectButton.sizeToFit()
return selectButton
}()
/// 商品图片
private lazy var iconView: UIImageView = {
let iconView = UIImageView()
iconView.layer.cornerRadius = 30
iconView.layer.masksToBounds = true
return iconView
}()
/// 商品标题
private lazy var titleLabel: UILabel = {
let titleLabel = UILabel()
return titleLabel
}()
/// 新价格标签
private lazy var newPriceLabel: UILabel = {
let newPriceLabel = UILabel()
newPriceLabel.textColor = UIColor.redColor()
return newPriceLabel
}()
// 老价格标签
private lazy var oldPriceLabel: JFOldPriceLabel = {
let oldPriceLabel = JFOldPriceLabel()
oldPriceLabel.textColor = UIColor.grayColor()
return oldPriceLabel
}()
// 加减操作的view
private lazy var addAndsubtraction: UIView = {
let addAndsubtraction = UIView()
addAndsubtraction.backgroundColor = UIColor(white: 0.9, alpha: 0.8)
return addAndsubtraction
}()
// 减号按钮
private lazy var subtractionButton: UIButton = {
let subtractionButton = UIButton(type: UIButtonType.Custom)
subtractionButton.tag = 10;
subtractionButton.setBackgroundImage(UIImage(named: "subtraction_icon"), forState: UIControlState.Normal)
subtractionButton.addTarget(self, action: "didTappedCalculateButton:", forControlEvents: UIControlEvents.TouchUpInside)
return subtractionButton
}()
// 显示数量lbael
private lazy var goodCountLabel: UILabel = {
let goodCountLabel = UILabel()
goodCountLabel.textAlignment = NSTextAlignment.Center
return goodCountLabel
}()
// 加号按钮
private lazy var addButton: UIButton = {
let addButton = UIButton(type: UIButtonType.Custom)
addButton.tag = 11
addButton.setBackgroundImage(UIImage(named: "add_icon"), forState: UIControlState.Normal)
addButton.addTarget(self, action: "didTappedCalculateButton:", forControlEvents: UIControlEvents.TouchUpInside)
return addButton
}()
}
================================================
FILE: shoppingCart/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
</array>
</dict>
</plist>
================================================
FILE: shoppingCart.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
A57AB3E01BFB6C3100012F62 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A57AB3DF1BFB6C3100012F62 /* AppDelegate.swift */; };
A57AB3E71BFB6C3100012F62 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A57AB3E61BFB6C3100012F62 /* Assets.xcassets */; };
A57AB3EA1BFB6C3100012F62 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A57AB3E81BFB6C3100012F62 /* LaunchScreen.storyboard */; };
A57AB4181BFB6E6500012F62 /* Constraint.swift in Sources */ = {isa = PBXBuildFile; fileRef = A57AB4091BFB6E6500012F62 /* Constraint.swift */; };
A57AB4191BFB6E6500012F62 /* ConstraintAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = A57AB40A1BFB6E6500012F62 /* ConstraintAttributes.swift */; };
A57AB41A1BFB6E6500012F62 /* ConstraintDescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = A57AB40B1BFB6E6500012F62 /* ConstraintDescription.swift */; };
A57AB41B1BFB6E6500012F62 /* ConstraintItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = A57AB40C1BFB6E6500012F62 /* ConstraintItem.swift */; };
A57AB41C1BFB6E6500012F62 /* ConstraintMaker.swift in Sources */ = {isa = PBXBuildFile; fileRef = A57AB40D1BFB6E6500012F62 /* ConstraintMaker.swift */; };
A57AB41D1BFB6E6500012F62 /* ConstraintRelation.swift in Sources */ = {isa = PBXBuildFile; fileRef = A57AB40E1BFB6E6500012F62 /* ConstraintRelation.swift */; };
A57AB41E1BFB6E6500012F62 /* Debugging.swift in Sources */ = {isa = PBXBuildFile; fileRef = A57AB40F1BFB6E6500012F62 /* Debugging.swift */; };
A57AB41F1BFB6E6500012F62 /* EdgeInsets.swift in Sources */ = {isa = PBXBuildFile; fileRef = A57AB4101BFB6E6500012F62 /* EdgeInsets.swift */; };
A57AB4211BFB6E6500012F62 /* LayoutConstraint.swift in Sources */ = {isa = PBXBuildFile; fileRef = A57AB4121BFB6E6500012F62 /* LayoutConstraint.swift */; };
A57AB4221BFB6E6500012F62 /* SnapKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = A57AB4141BFB6E6500012F62 /* SnapKit.swift */; };
A57AB4231BFB6E6500012F62 /* SourceLocation.swift in Sources */ = {isa = PBXBuildFile; fileRef = A57AB4151BFB6E6500012F62 /* SourceLocation.swift */; };
A57AB4241BFB6E6500012F62 /* View+SnapKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = A57AB4161BFB6E6500012F62 /* View+SnapKit.swift */; };
A57AB4251BFB6E6500012F62 /* ViewController+SnapKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = A57AB4171BFB6E6500012F62 /* ViewController+SnapKit.swift */; };
A59F9BBC1BFCD30E0076221A /* JFGoodModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59F9BBB1BFCD30E0076221A /* JFGoodModel.swift */; };
A59F9BCA1BFCD3220076221A /* JFGoodListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59F9BBF1BFCD3220076221A /* JFGoodListViewController.swift */; };
A59F9BCB1BFCD3220076221A /* JFGoodListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59F9BC21BFCD3220076221A /* JFGoodListCell.swift */; };
A59F9BCC1BFCD3220076221A /* JFShoppingCartViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59F9BC51BFCD3220076221A /* JFShoppingCartViewController.swift */; };
A59F9BCD1BFCD3220076221A /* JFOldPriceLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59F9BC81BFCD3220076221A /* JFOldPriceLabel.swift */; };
A59F9BCE1BFCD3220076221A /* JFShoppingCartCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59F9BC91BFCD3220076221A /* JFShoppingCartCell.swift */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
A57AB3DC1BFB6C3100012F62 /* shoppingCart.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = shoppingCart.app; sourceTree = BUILT_PRODUCTS_DIR; };
A57AB3DF1BFB6C3100012F62 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
A57AB3E61BFB6C3100012F62 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
A57AB3E91BFB6C3100012F62 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
A57AB3EB1BFB6C3100012F62 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
A57AB4091BFB6E6500012F62 /* Constraint.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Constraint.swift; sourceTree = "<group>"; };
A57AB40A1BFB6E6500012F62 /* ConstraintAttributes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConstraintAttributes.swift; sourceTree = "<group>"; };
A57AB40B1BFB6E6500012F62 /* ConstraintDescription.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConstraintDescription.swift; sourceTree = "<group>"; };
A57AB40C1BFB6E6500012F62 /* ConstraintItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConstraintItem.swift; sourceTree = "<group>"; };
A57AB40D1BFB6E6500012F62 /* ConstraintMaker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConstraintMaker.swift; sourceTree = "<group>"; };
A57AB40E1BFB6E6500012F62 /* ConstraintRelation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConstraintRelation.swift; sourceTree = "<group>"; };
A57AB40F1BFB6E6500012F62 /* Debugging.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Debugging.swift; sourceTree = "<group>"; };
A57AB4101BFB6E6500012F62 /* EdgeInsets.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EdgeInsets.swift; sourceTree = "<group>"; };
A57AB4121BFB6E6500012F62 /* LayoutConstraint.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LayoutConstraint.swift; sourceTree = "<group>"; };
A57AB4131BFB6E6500012F62 /* SnapKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SnapKit.h; sourceTree = "<group>"; };
A57AB4141BFB6E6500012F62 /* SnapKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SnapKit.swift; sourceTree = "<group>"; };
A57AB4151BFB6E6500012F62 /* SourceLocation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SourceLocation.swift; sourceTree = "<group>"; };
A57AB4161BFB6E6500012F62 /* View+SnapKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "View+SnapKit.swift"; sourceTree = "<group>"; };
A57AB4171BFB6E6500012F62 /* ViewController+SnapKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ViewController+SnapKit.swift"; sourceTree = "<group>"; };
A59F9BBB1BFCD30E0076221A /* JFGoodModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JFGoodModel.swift; sourceTree = "<group>"; };
A59F9BBF1BFCD3220076221A /* JFGoodListViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JFGoodListViewController.swift; sourceTree = "<group>"; };
A59F9BC21BFCD3220076221A /* JFGoodListCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JFGoodListCell.swift; sourceTree = "<group>"; };
A59F9BC51BFCD3220076221A /* JFShoppingCartViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JFShoppingCartViewController.swift; sourceTree = "<group>"; };
A59F9BC81BFCD3220076221A /* JFOldPriceLabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JFOldPriceLabel.swift; sourceTree = "<group>"; };
A59F9BC91BFCD3220076221A /* JFShoppingCartCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JFShoppingCartCell.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
A57AB3D91BFB6C3100012F62 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
A57AB3D31BFB6C3100012F62 = {
isa = PBXGroup;
children = (
A57AB3DE1BFB6C3100012F62 /* shoppingCart */,
A57AB3DD1BFB6C3100012F62 /* Products */,
);
sourceTree = "<group>";
};
A57AB3DD1BFB6C3100012F62 /* Products */ = {
isa = PBXGroup;
children = (
A57AB3DC1BFB6C3100012F62 /* shoppingCart.app */,
);
name = Products;
sourceTree = "<group>";
};
A57AB3DE1BFB6C3100012F62 /* shoppingCart */ = {
isa = PBXGroup;
children = (
A57AB3FA1BFB6DB600012F62 /* Classes */,
A57AB3DF1BFB6C3100012F62 /* AppDelegate.swift */,
A57AB3E61BFB6C3100012F62 /* Assets.xcassets */,
A57AB3E81BFB6C3100012F62 /* LaunchScreen.storyboard */,
A57AB3EB1BFB6C3100012F62 /* Info.plist */,
);
path = shoppingCart;
sourceTree = "<group>";
};
A57AB3FA1BFB6DB600012F62 /* Classes */ = {
isa = PBXGroup;
children = (
A59F9BBD1BFCD3220076221A /* GoodList */,
A59F9BC31BFCD3220076221A /* ShopCart */,
A59F9BBA1BFCD30E0076221A /* Model */,
A57AB3FF1BFB6DB600012F62 /* Library */,
);
path = Classes;
sourceTree = "<group>";
};
A57AB3FF1BFB6DB600012F62 /* Library */ = {
isa = PBXGroup;
children = (
A57AB4081BFB6E6500012F62 /* SnapKit */,
);
path = Library;
sourceTree = "<group>";
};
A57AB4081BFB6E6500012F62 /* SnapKit */ = {
isa = PBXGroup;
children = (
A57AB4091BFB6E6500012F62 /* Constraint.swift */,
A57AB40A1BFB6E6500012F62 /* ConstraintAttributes.swift */,
A57AB40B1BFB6E6500012F62 /* ConstraintDescription.swift */,
A57AB40C1BFB6E6500012F62 /* ConstraintItem.swift */,
A57AB40D1BFB6E6500012F62 /* ConstraintMaker.swift */,
A57AB40E1BFB6E6500012F62 /* ConstraintRelation.swift */,
A57AB40F1BFB6E6500012F62 /* Debugging.swift */,
A57AB4101BFB6E6500012F62 /* EdgeInsets.swift */,
A57AB4121BFB6E6500012F62 /* LayoutConstraint.swift */,
A57AB4131BFB6E6500012F62 /* SnapKit.h */,
A57AB4141BFB6E6500012F62 /* SnapKit.swift */,
A57AB4151BFB6E6500012F62 /* SourceLocation.swift */,
A57AB4161BFB6E6500012F62 /* View+SnapKit.swift */,
A57AB4171BFB6E6500012F62 /* ViewController+SnapKit.swift */,
);
path = SnapKit;
sourceTree = "<group>";
};
A59F9BBA1BFCD30E0076221A /* Model */ = {
isa = PBXGroup;
children = (
A59F9BBB1BFCD30E0076221A /* JFGoodModel.swift */,
);
path = Model;
sourceTree = "<group>";
};
A59F9BBD1BFCD3220076221A /* GoodList */ = {
isa = PBXGroup;
children = (
A59F9BBE1BFCD3220076221A /* Controller */,
A59F9BC01BFCD3220076221A /* Model */,
A59F9BC11BFCD3220076221A /* View */,
);
path = GoodList;
sourceTree = "<group>";
};
A59F9BBE1BFCD3220076221A /* Controller */ = {
isa = PBXGroup;
children = (
A59F9BBF1BFCD3220076221A /* JFGoodListViewController.swift */,
);
path = Controller;
sourceTree = "<group>";
};
A59F9BC01BFCD3220076221A /* Model */ = {
isa = PBXGroup;
children = (
);
path = Model;
sourceTree = "<group>";
};
A59F9BC11BFCD3220076221A /* View */ = {
isa = PBXGroup;
children = (
A59F9BC21BFCD3220076221A /* JFGoodListCell.swift */,
);
path = View;
sourceTree = "<group>";
};
A59F9BC31BFCD3220076221A /* ShopCart */ = {
isa = PBXGroup;
children = (
A59F9BC41BFCD3220076221A /* Controller */,
A59F9BC61BFCD3220076221A /* Model */,
A59F9BC71BFCD3220076221A /* View */,
);
path = ShopCart;
sourceTree = "<group>";
};
A59F9BC41BFCD3220076221A /* Controller */ = {
isa = PBXGroup;
children = (
A59F9BC51BFCD3220076221A /* JFShoppingCartViewController.swift */,
);
path = Controller;
sourceTree = "<group>";
};
A59F9BC61BFCD3220076221A /* Model */ = {
isa = PBXGroup;
children = (
);
path = Model;
sourceTree = "<group>";
};
A59F9BC71BFCD3220076221A /* View */ = {
isa = PBXGroup;
children = (
A59F9BC81BFCD3220076221A /* JFOldPriceLabel.swift */,
A59F9BC91BFCD3220076221A /* JFShoppingCartCell.swift */,
);
path = View;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
A57AB3DB1BFB6C3100012F62 /* shoppingCart */ = {
isa = PBXNativeTarget;
buildConfigurationList = A57AB3EE1BFB6C3100012F62 /* Build configuration list for PBXNativeTarget "shoppingCart" */;
buildPhases = (
A57AB3D81BFB6C3100012F62 /* Sources */,
A57AB3D91BFB6C3100012F62 /* Frameworks */,
A57AB3DA1BFB6C3100012F62 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = shoppingCart;
productName = shoppingCart;
productReference = A57AB3DC1BFB6C3100012F62 /* shoppingCart.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
A57AB3D41BFB6C3100012F62 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0710;
LastUpgradeCheck = 0710;
ORGANIZATIONNAME = "六阿哥";
TargetAttributes = {
A57AB3DB1BFB6C3100012F62 = {
CreatedOnToolsVersion = 7.1;
DevelopmentTeam = GABKPEQD3S;
};
};
};
buildConfigurationList = A57AB3D71BFB6C3100012F62 /* Build configuration list for PBXProject "shoppingCart" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = A57AB3D31BFB6C3100012F62;
productRefGroup = A57AB3DD1BFB6C3100012F62 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
A57AB3DB1BFB6C3100012F62 /* shoppingCart */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
A57AB3DA1BFB6C3100012F62 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
A57AB3EA1BFB6C3100012F62 /* LaunchScreen.storyboard in Resources */,
A57AB3E71BFB6C3100012F62 /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
A57AB3D81BFB6C3100012F62 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
A57AB41B1BFB6E6500012F62 /* ConstraintItem.swift in Sources */,
A57AB4231BFB6E6500012F62 /* SourceLocation.swift in Sources */,
A59F9BBC1BFCD30E0076221A /* JFGoodModel.swift in Sources */,
A57AB41D1BFB6E6500012F62 /* ConstraintRelation.swift in Sources */,
A57AB4221BFB6E6500012F62 /* SnapKit.swift in Sources */,
A59F9BCE1BFCD3220076221A /* JFShoppingCartCell.swift in Sources */,
A57AB41E1BFB6E6500012F62 /* Debugging.swift in Sources */,
A59F9BCD1BFCD3220076221A /* JFOldPriceLabel.swift in Sources */,
A57AB41F1BFB6E6500012F62 /* EdgeInsets.swift in Sources */,
A57AB4181BFB6E6500012F62 /* Constraint.swift in Sources */,
A57AB3E01BFB6C3100012F62 /* AppDelegate.swift in Sources */,
A57AB4191BFB6E6500012F62 /* ConstraintAttributes.swift in Sources */,
A57AB4211BFB6E6500012F62 /* LayoutConstraint.swift in Sources */,
A57AB4251BFB6E6500012F62 /* ViewController+SnapKit.swift in Sources */,
A59F9BCC1BFCD3220076221A /* JFShoppingCartViewController.swift in Sources */,
A57AB4241BFB6E6500012F62 /* View+SnapKit.swift in Sources */,
A59F9BCA1BFCD3220076221A /* JFGoodListViewController.swift in Sources */,
A57AB41C1BFB6E6500012F62 /* ConstraintMaker.swift in Sources */,
A57AB41A1BFB6E6500012F62 /* ConstraintDescription.swift in Sources */,
A59F9BCB1BFCD3220076221A /* JFGoodListCell.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
A57AB3E81BFB6C3100012F62 /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
A57AB3E91BFB6C3100012F62 /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
A57AB3EC1BFB6C3100012F62 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.1;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
A57AB3ED1BFB6C3100012F62 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.1;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
A57AB3EF1BFB6C3100012F62 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = shoppingCart/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = cn.6ag.shoppingCart;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
A57AB3F01BFB6C3100012F62 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = shoppingCart/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = cn.6ag.shoppingCart;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
A57AB3D71BFB6C3100012F62 /* Build configuration list for PBXProject "shoppingCart" */ = {
isa = XCConfigurationList;
buildConfigurations = (
A57AB3EC1BFB6C3100012F62 /* Debug */,
A57AB3ED1BFB6C3100012F62 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
A57AB3EE1BFB6C3100012F62 /* Build configuration list for PBXNativeTarget "shoppingCart" */ = {
isa = XCConfigurationList;
buildConfigurations = (
A57AB3EF1BFB6C3100012F62 /* Debug */,
A57AB3F01BFB6C3100012F62 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = A57AB3D41BFB6C3100012F62 /* Project object */;
}
================================================
FILE: shoppingCart.xcodeproj/project.xcworkspace/contents.xcworkspacedata
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:shoppingCart.xcodeproj">
</FileRef>
</Workspace>
================================================
FILE: shoppingCart.xcodeproj/xcuserdata/jianfeng.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Bucket
type = "1"
version = "2.0">
<Breakpoints>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.SwiftErrorBreakpoint">
<BreakpointContent
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No">
</BreakpointContent>
</BreakpointProxy>
</Breakpoints>
</Bucket>
================================================
FILE: shoppingCart.xcodeproj/xcuserdata/jianfeng.xcuserdatad/xcschemes/shoppingCart.xcscheme
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0710"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "A57AB3DB1BFB6C3100012F62"
BuildableName = "shoppingCart.app"
BlueprintName = "shoppingCart"
ReferencedContainer = "container:shoppingCart.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "A57AB3DB1BFB6C3100012F62"
BuildableName = "shoppingCart.app"
BlueprintName = "shoppingCart"
ReferencedContainer = "container:shoppingCart.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "A57AB3DB1BFB6C3100012F62"
BuildableName = "shoppingCart.app"
BlueprintName = "shoppingCart"
ReferencedContainer = "container:shoppingCart.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "A57AB3DB1BFB6C3100012F62"
BuildableName = "shoppingCart.app"
BlueprintName = "shoppingCart"
ReferencedContainer = "container:shoppingCart.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
================================================
FILE: shoppingCart.xcodeproj/xcuserdata/jianfeng.xcuserdatad/xcschemes/xcschememanagement.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SchemeUserState</key>
<dict>
<key>shoppingCart.xcscheme</key>
<dict>
<key>orderHint</key>
<integer>0</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
<dict>
<key>A57AB3DB1BFB6C3100012F62</key>
<dict>
<key>primary</key>
<true/>
</dict>
</dict>
</dict>
</plist>
gitextract_3739o5f2/
├── README.md
├── shoppingCart/
│ ├── AppDelegate.swift
│ ├── Assets.xcassets/
│ │ ├── AppIcon.appiconset/
│ │ │ └── Contents.json
│ │ ├── Contents.json
│ │ ├── add_icon.imageset/
│ │ │ └── Contents.json
│ │ ├── button_cart.imageset/
│ │ │ └── Contents.json
│ │ ├── button_cart_add.imageset/
│ │ │ └── Contents.json
│ │ ├── check_n.imageset/
│ │ │ └── Contents.json
│ │ ├── check_y.imageset/
│ │ │ └── Contents.json
│ │ ├── delete_icon.imageset/
│ │ │ └── Contents.json
│ │ ├── goodicon_0.imageset/
│ │ │ └── Contents.json
│ │ ├── goodicon_1.imageset/
│ │ │ └── Contents.json
│ │ ├── goodicon_2.imageset/
│ │ │ └── Contents.json
│ │ ├── goodicon_3.imageset/
│ │ │ └── Contents.json
│ │ ├── goodicon_4.imageset/
│ │ │ └── Contents.json
│ │ ├── goodicon_5.imageset/
│ │ │ └── Contents.json
│ │ ├── goodicon_6.imageset/
│ │ │ └── Contents.json
│ │ ├── goodicon_7.imageset/
│ │ │ └── Contents.json
│ │ ├── goodicon_8.imageset/
│ │ │ └── Contents.json
│ │ ├── goodicon_9.imageset/
│ │ │ └── Contents.json
│ │ ├── numbe_bg_icon.imageset/
│ │ │ └── Contents.json
│ │ └── subtraction_icon.imageset/
│ │ └── Contents.json
│ ├── Base.lproj/
│ │ └── LaunchScreen.storyboard
│ ├── Classes/
│ │ ├── GoodList/
│ │ │ ├── Controller/
│ │ │ │ └── JFGoodListViewController.swift
│ │ │ └── View/
│ │ │ └── JFGoodListCell.swift
│ │ ├── Library/
│ │ │ └── SnapKit/
│ │ │ ├── Constraint.swift
│ │ │ ├── ConstraintAttributes.swift
│ │ │ ├── ConstraintDescription.swift
│ │ │ ├── ConstraintItem.swift
│ │ │ ├── ConstraintMaker.swift
│ │ │ ├── ConstraintRelation.swift
│ │ │ ├── Debugging.swift
│ │ │ ├── EdgeInsets.swift
│ │ │ ├── LayoutConstraint.swift
│ │ │ ├── SnapKit.h
│ │ │ ├── SnapKit.swift
│ │ │ ├── SourceLocation.swift
│ │ │ ├── View+SnapKit.swift
│ │ │ └── ViewController+SnapKit.swift
│ │ ├── Model/
│ │ │ └── JFGoodModel.swift
│ │ └── ShopCart/
│ │ ├── Controller/
│ │ │ └── JFShoppingCartViewController.swift
│ │ └── View/
│ │ ├── JFOldPriceLabel.swift
│ │ └── JFShoppingCartCell.swift
│ └── Info.plist
└── shoppingCart.xcodeproj/
├── project.pbxproj
├── project.xcworkspace/
│ ├── contents.xcworkspacedata
│ └── xcuserdata/
│ └── jianfeng.xcuserdatad/
│ └── UserInterfaceState.xcuserstate
└── xcuserdata/
└── jianfeng.xcuserdatad/
├── xcdebugger/
│ └── Breakpoints_v2.xcbkptlist
└── xcschemes/
├── shoppingCart.xcscheme
└── xcschememanagement.plist
Condensed preview — 50 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (170K chars).
[
{
"path": "README.md",
"chars": 154,
"preview": "# shoppingCart\n\n## swift的购物车demo\n采用纯代码UI,autolayout自动布局,core animation动画效果。\n\n 2011-Present SnapKit Team - https://github.com/SnapKit\n//\n// Permission is hereby g"
},
{
"path": "shoppingCart/Classes/Library/SnapKit/ConstraintAttributes.swift",
"chars": 7539,
"preview": "//\n// SnapKit\n//\n// Copyright (c) 2011-2015 SnapKit Team - https://github.com/SnapKit\n//\n// Permission is hereby gran"
},
{
"path": "shoppingCart/Classes/Library/SnapKit/ConstraintDescription.swift",
"chars": 19955,
"preview": "//\n// SnapKit\n//\n// Copyright (c) 2011-2015 SnapKit Team - https://github.com/SnapKit\n//\n// Permission is hereby gran"
},
{
"path": "shoppingCart/Classes/Library/SnapKit/ConstraintItem.swift",
"chars": 2123,
"preview": "//\n// SnapKit\n//\n// Copyright (c) 2011-2015 SnapKit Team - https://github.com/SnapKit\n//\n// Permission is hereby gran"
},
{
"path": "shoppingCart/Classes/Library/SnapKit/ConstraintMaker.swift",
"chars": 8881,
"preview": "//\n// SnapKit\n//\n// Copyright (c) 2011-2015 SnapKit Team - https://github.com/SnapKit\n//\n// Permission is hereby gran"
},
{
"path": "shoppingCart/Classes/Library/SnapKit/ConstraintRelation.swift",
"chars": 1729,
"preview": "//\n// SnapKit\n//\n// Copyright (c) 2011-2015 SnapKit Team - https://github.com/SnapKit\n//\n// Permission is hereby gran"
},
{
"path": "shoppingCart/Classes/Library/SnapKit/Debugging.swift",
"chars": 6696,
"preview": "//\n// SnapKit\n//\n// Copyright (c) 2011-2015 SnapKit Team - https://github.com/SnapKit\n//\n// Permission is hereby gran"
},
{
"path": "shoppingCart/Classes/Library/SnapKit/EdgeInsets.swift",
"chars": 1845,
"preview": "//\n// SnapKit\n//\n// Copyright (c) 2011-2015 SnapKit Team - https://github.com/SnapKit\n//\n// Permission is hereby gran"
},
{
"path": "shoppingCart/Classes/Library/SnapKit/LayoutConstraint.swift",
"chars": 2176,
"preview": "//\n// SnapKit\n//\n// Copyright (c) 2011-2015 SnapKit Team - https://github.com/SnapKit\n//\n// Permission is hereby gran"
},
{
"path": "shoppingCart/Classes/Library/SnapKit/SnapKit.h",
"chars": 1325,
"preview": "//\n// SnapKit\n//\n// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit\n//\n// Permission is hereby g"
},
{
"path": "shoppingCart/Classes/Library/SnapKit/SnapKit.swift",
"chars": 1688,
"preview": "//\n// SnapKit\n//\n// Copyright (c) 2011-2015 SnapKit Team - https://github.com/SnapKit\n//\n// Permission is hereby gran"
},
{
"path": "shoppingCart/Classes/Library/SnapKit/SourceLocation.swift",
"chars": 1379,
"preview": "//\n// SnapKit\n//\n// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit\n//\n// Permission is hereby g"
},
{
"path": "shoppingCart/Classes/Library/SnapKit/View+SnapKit.swift",
"chars": 8583,
"preview": "//\n// SnapKit\n//\n// Copyright (c) 2011-2015 SnapKit Team - https://github.com/SnapKit\n//\n// Permission is hereby gran"
},
{
"path": "shoppingCart/Classes/Library/SnapKit/ViewController+SnapKit.swift",
"chars": 2080,
"preview": "//\n// SnapKit\n//\n// Copyright (c) 2011-2015 SnapKit Team - https://github.com/SnapKit\n//\n// Permission is hereby gran"
},
{
"path": "shoppingCart/Classes/Model/JFGoodModel.swift",
"chars": 842,
"preview": "//\n// JFGoodModel.swift\n// shoppingCart\n//\n// Created by jianfeng on 15/11/17.\n// Copyright © 2015年 六阿哥. All rights "
},
{
"path": "shoppingCart/Classes/ShopCart/Controller/JFShoppingCartViewController.swift",
"chars": 8419,
"preview": "//\n// JFShoppingCartViewController.swift\n// shoppingCart\n//\n// Created by jianfeng on 15/11/17.\n// Copyright © 2015年"
},
{
"path": "shoppingCart/Classes/ShopCart/View/JFOldPriceLabel.swift",
"chars": 545,
"preview": "//\n// JFOldPriceLabel.swift\n// shoppingCart\n//\n// Created by jianfeng on 15/11/18.\n// Copyright © 2015年 六阿哥. All rig"
},
{
"path": "shoppingCart/Classes/ShopCart/View/JFShoppingCartCell.swift",
"chars": 7161,
"preview": "//\n// JFShoppingCartCell.swift\n// shoppingCart\n//\n// Created by jianfeng on 15/11/18.\n// Copyright © 2015年 六阿哥. All "
},
{
"path": "shoppingCart/Info.plist",
"chars": 1038,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "shoppingCart.xcodeproj/project.pbxproj",
"chars": 21264,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
},
{
"path": "shoppingCart.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
"chars": 157,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"self:shoppingCart.xc"
},
{
"path": "shoppingCart.xcodeproj/xcuserdata/jianfeng.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist",
"chars": 420,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Bucket\n type = \"1\"\n version = \"2.0\">\n <Breakpoints>\n <BreakpointProxy"
},
{
"path": "shoppingCart.xcodeproj/xcuserdata/jianfeng.xcuserdatad/xcschemes/shoppingCart.xcscheme",
"chars": 3363,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n LastUpgradeVersion = \"0710\"\n version = \"1.3\">\n <BuildAction\n "
},
{
"path": "shoppingCart.xcodeproj/xcuserdata/jianfeng.xcuserdatad/xcschemes/xcschememanagement.plist",
"chars": 484,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
}
]
// ... and 1 more files (download for full content)
About this extraction
This page contains the full source code of the 6ag/shoppingCart GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 50 files (151.8 KB), approximately 39.8k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.