Showing preview only (293K chars total). Download the full file or copy to clipboard to get everything.
Repository: DragonTnT/appstore-clone
Branch: master
Commit: 7166ceba69b6
Files: 102
Total size: 261.2 KB
Directory structure:
gitextract_vi5lwdol/
├── AppStoreDemo/
│ ├── AppDelegate.swift
│ ├── Assets.xcassets/
│ │ ├── AppIcon.appiconset/
│ │ │ └── Contents.json
│ │ ├── Contents.json
│ │ ├── DS_Store
│ │ ├── app_logo/
│ │ │ ├── Contents.json
│ │ │ ├── logo_broadcast.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── logo_car.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── logo_game.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── logo_jump.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── logo_smile.imageset/
│ │ │ │ └── Contents.json
│ │ │ └── logo_weibo.imageset/
│ │ │ └── Contents.json
│ │ ├── common/
│ │ │ ├── Contents.json
│ │ │ ├── circle_download.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── close_button.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── demo_icon.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── detail_download.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── detail_more.imageset/
│ │ │ │ └── Contents.json
│ │ │ └── navigation_back.imageset/
│ │ │ └── Contents.json
│ │ ├── cover/
│ │ │ ├── Contents.json
│ │ │ ├── cover_1.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── cover_2.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── cover_3.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── cover_4.imageset/
│ │ │ │ └── Contents.json
│ │ │ └── cover_5.imageset/
│ │ │ └── Contents.json
│ │ ├── cover_detail/
│ │ │ ├── Contents.json
│ │ │ ├── cover_detail.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── cover_detail1.imageset/
│ │ │ │ └── Contents.json
│ │ │ └── cover_detail2.imageset/
│ │ │ └── Contents.json
│ │ └── tabBar/
│ │ ├── Contents.json
│ │ ├── tabbar_apps.imageset/
│ │ │ └── Contents.json
│ │ ├── tabbar_games.imageset/
│ │ │ └── Contents.json
│ │ ├── tabbar_search.imageset/
│ │ │ └── Contents.json
│ │ ├── tabbar_today.imageset/
│ │ │ └── Contents.json
│ │ └── tabbar_updates.imageset/
│ │ └── Contents.json
│ ├── Base.lproj/
│ │ └── LaunchScreen.storyboard
│ ├── Common/
│ │ ├── CommonCollectionFlowLayout.swift
│ │ └── CommonSectionHeaderView.swift
│ ├── Extension/
│ │ ├── String+Extension.swift
│ │ ├── UIColor+Extension.swift
│ │ ├── UITableView+Extension.swift
│ │ ├── UIView+Extension.swift
│ │ └── UIViewController+Extension.swift
│ ├── Game/
│ │ ├── Controller/
│ │ │ ├── DetailViewController.swift
│ │ │ ├── DownloadPresentationController.swift
│ │ │ ├── DownloadViewController.swift
│ │ │ └── GameTableViewController.swift
│ │ ├── Model/
│ │ │ ├── DownloadTransitioning.swift
│ │ │ ├── GameRecommandModel.swift
│ │ │ └── GameTopicModel.swift
│ │ └── View/
│ │ ├── Detail/
│ │ │ ├── DetailInfomationTableViewCell.swift
│ │ │ ├── DetailInformationCell.swift
│ │ │ ├── DetailNavigationView.swift
│ │ │ ├── DetailNewFeaturesCell.swift
│ │ │ ├── DetailNewFeaturesCell.xib
│ │ │ ├── DetailPreviewCell.swift
│ │ │ ├── DetailPreviewCollectionView.swift
│ │ │ ├── DetailPreviewCollectionViewCell.swift
│ │ │ ├── DetailTopInfoCell.swift
│ │ │ └── DetailTopInfoCell.xib
│ │ ├── Download/
│ │ │ ├── DownloadBottomView.swift
│ │ │ ├── DownloadBottomView.xib
│ │ │ ├── DownloadClickView.swift
│ │ │ └── DownloadClickView.xib
│ │ ├── Link/
│ │ │ ├── GameLinkTableView.swift
│ │ │ └── GameLinkTableViewCell.swift
│ │ ├── Recommand/
│ │ │ ├── GameRecommandCollectionView.swift
│ │ │ ├── GameRecommandTableViewCell.swift
│ │ │ ├── RecommandCollectionViewCell.swift
│ │ │ └── RecommandCollectionViewCell.xib
│ │ └── Topic/
│ │ ├── GameTopicCollectionView.swift
│ │ ├── GameTopicCollectionViewCell.swift
│ │ ├── GameTopicCollectionViewCell.xib
│ │ └── GameTopicTableViewCell.swift
│ ├── Info.plist
│ ├── Main.storyboard
│ ├── Search/
│ │ ├── Controller/
│ │ │ └── SearchTableViewController.swift
│ │ └── View/
│ │ └── SearchTableViewCell.swift
│ ├── Today/
│ │ ├── Controller/
│ │ │ ├── CardDetailViewController.swift
│ │ │ ├── CardPresentationController.swift
│ │ │ └── TodayViewController.swift
│ │ ├── Model/
│ │ │ ├── DS_Store
│ │ │ └── TodayAnimationTransition.swift
│ │ └── View/
│ │ ├── DetailScrollView.swift
│ │ ├── TodayTableHeaderView.swift
│ │ └── TodayTableViewCell.swift
│ ├── Update/
│ │ ├── Controller/
│ │ │ └── UpdateTableViewController.swift
│ │ ├── Model/
│ │ │ └── UpdateModel.swift
│ │ └── View/
│ │ ├── UpdateTableViewCell.swift
│ │ └── UpdateTableViewCell.xib
│ ├── User/
│ │ ├── Controller/
│ │ │ └── UserTableViewController.swift
│ │ └── View/
│ │ └── User.storyboard
│ └── Utils/
│ ├── GlobalConstants.swift
│ ├── GlobalFunctions.swift
│ └── StarView.swift
├── AppStoreDemo.xcodeproj/
│ ├── project.pbxproj
│ ├── project.xcworkspace/
│ │ ├── contents.xcworkspacedata
│ │ ├── xcshareddata/
│ │ │ └── IDEWorkspaceChecks.plist
│ │ └── xcuserdata/
│ │ └── fengbufang.xcuserdatad/
│ │ └── UserInterfaceState.xcuserstate
│ └── xcuserdata/
│ └── fengbufang.xcuserdatad/
│ ├── xcdebugger/
│ │ └── Breakpoints_v2.xcbkptlist
│ └── xcschemes/
│ └── xcschememanagement.plist
├── README.md
└── 中文简介.md
================================================
FILE CONTENTS
================================================
================================================
FILE: AppStoreDemo/AppDelegate.swift
================================================
//
// AppDelegate.swift
// AppStoreDemo
//
// Created by Allen long on 2019/7/31.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
setStatusBarColor(.white)
return true
}
}
================================================
FILE: AppStoreDemo/Assets.xcassets/AppIcon.appiconset/Contents.json
================================================
{
"images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "AppStore-120.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "AppStore-180.png",
"scale" : "3x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "83.5x83.5",
"scale" : "2x"
},
{
"idiom" : "ios-marketing",
"size" : "1024x1024",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: AppStoreDemo/Assets.xcassets/Contents.json
================================================
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: AppStoreDemo/Assets.xcassets/app_logo/Contents.json
================================================
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: AppStoreDemo/Assets.xcassets/app_logo/logo_broadcast.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "logo_broadcast.jpeg",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: AppStoreDemo/Assets.xcassets/app_logo/logo_car.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "logo_car.jpg",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: AppStoreDemo/Assets.xcassets/app_logo/logo_game.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "logo_game.jpg",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: AppStoreDemo/Assets.xcassets/app_logo/logo_jump.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "logo_jump.jpg",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: AppStoreDemo/Assets.xcassets/app_logo/logo_smile.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "logo_smile.jpg",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: AppStoreDemo/Assets.xcassets/app_logo/logo_weibo.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "logo_weibo.jpeg",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: AppStoreDemo/Assets.xcassets/common/Contents.json
================================================
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: AppStoreDemo/Assets.xcassets/common/circle_download.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "circle_download@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "circle_download@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: AppStoreDemo/Assets.xcassets/common/close_button.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "close_button@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "close_button@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: AppStoreDemo/Assets.xcassets/common/demo_icon.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "demo_icon.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: AppStoreDemo/Assets.xcassets/common/detail_download.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "detail_download@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "detail_download@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: AppStoreDemo/Assets.xcassets/common/detail_more.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "detail_more@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "detail_more@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: AppStoreDemo/Assets.xcassets/common/navigation_back.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "navigation_back.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: AppStoreDemo/Assets.xcassets/cover/Contents.json
================================================
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: AppStoreDemo/Assets.xcassets/cover/cover_1.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "cover_1.jpeg",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: AppStoreDemo/Assets.xcassets/cover/cover_2.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "cover_2.jpeg",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: AppStoreDemo/Assets.xcassets/cover/cover_3.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "cover_3.jpeg",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: AppStoreDemo/Assets.xcassets/cover/cover_4.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "cover_4.jpeg",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: AppStoreDemo/Assets.xcassets/cover/cover_5.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "cover_5.jpeg",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: AppStoreDemo/Assets.xcassets/cover_detail/Contents.json
================================================
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: AppStoreDemo/Assets.xcassets/cover_detail/cover_detail.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "cover_detail.jpg",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: AppStoreDemo/Assets.xcassets/cover_detail/cover_detail1.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "cover_detail1.jpg",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: AppStoreDemo/Assets.xcassets/cover_detail/cover_detail2.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "cover_detail2.jpg",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: AppStoreDemo/Assets.xcassets/tabBar/Contents.json
================================================
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: AppStoreDemo/Assets.xcassets/tabBar/tabbar_apps.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "tabbar_apps@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "tabbar_apps@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: AppStoreDemo/Assets.xcassets/tabBar/tabbar_games.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "tabbar_games@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "tabbar_games@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: AppStoreDemo/Assets.xcassets/tabBar/tabbar_search.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "tabbar_search@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "tabbar_search@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: AppStoreDemo/Assets.xcassets/tabBar/tabbar_today.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "tabbar_today@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "tabbar_today@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: AppStoreDemo/Assets.xcassets/tabBar/tabbar_updates.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "tabbar_updates@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "tabbar_updates@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: AppStoreDemo/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="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
</document>
================================================
FILE: AppStoreDemo/Common/CommonCollectionFlowLayout.swift
================================================
//
// GameCollectionFlowLayout.swift
// AppStoreDemo
//
// Created by Allen long on 2019/8/6.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
class CommonCollectionFlowLayout: UICollectionViewFlowLayout {
init(itemSize: CGSize) {
super.init()
self.itemSize = itemSize
setupUI()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupUI() {
scrollDirection = UICollectionView.ScrollDirection.horizontal
minimumInteritemSpacing = 0
minimumLineSpacing = 10
sectionInset = UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 20)
}
override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
// Page width used for estimating and calculating paging.
let pageWidth = itemSize.width + minimumLineSpacing
// Make an estimation of the current page position.
let approximatePage = collectionView!.contentOffset.x/pageWidth
// Determine the current page based on velocity.
let currentPage = (velocity.x < 0.0) ? floor(approximatePage) : ceil(approximatePage)
// Create custom flickVelocity.
let flickVelocity = velocity.x * 0.3
// Check how many pages the user flicked, if <= 1 then flickedPages should return 0.
let flickedPages = (abs(round(flickVelocity)) <= 1) ? 0 : round(flickVelocity)
// Calculate newHorizontalOffset.
let newHorizontalOffset = ((currentPage + flickedPages) * pageWidth) - self.collectionView!.contentInset.left
return CGPoint(x: newHorizontalOffset, y: proposedContentOffset.y)
}
}
================================================
FILE: AppStoreDemo/Common/CommonSectionHeaderView.swift
================================================
//
// CommonSectionHeaderView.swift
// AppStoreDemo
//
// Created by Allen long on 2019/8/9.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
class CommonSectionHeaderView: UIView {
let topicLabel = UILabel()
let seeAllBtn = UIButton()
let lineView = UIView()
override init(frame: CGRect) {
super.init(frame: frame)
setupUI()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupUI() {
lineView.backgroundColor = GlobalConstants.speratorLineColor
lineView.frame = CGRect(x: GlobalConstants.leftMargin, y: 0, width: kScreenW - 2 * GlobalConstants.leftMargin, height: 0.8)
topicLabel.frame = CGRect(x: 20, y: 13, width: 200, height: 24)
topicLabel.font = UIFont.systemFont(ofSize: 22.0, weight: .medium)
topicLabel.textColor = UIColor.black
seeAllBtn.setTitleColor(GlobalConstants.textBlueColor, for: .normal)
seeAllBtn.setTitle("See All", for: .normal)
seeAllBtn.titleLabel?.font = UIFont.systemFont(ofSize: 17)
seeAllBtn.frame = CGRect(x: kScreenW - GlobalConstants.leftMargin - 72, y: 16, width: 72, height: 22)
addSubview(lineView)
addSubview(topicLabel)
addSubview(seeAllBtn)
}
func changeSectionTitle(with title: String) {
topicLabel.text = title
}
}
================================================
FILE: AppStoreDemo/Extension/String+Extension.swift
================================================
//
// String+Extension.swift
// AppStoreDemo
//
// Created by Allen long on 2019/8/2.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
extension String {
/// Calculate text's height from `width` and `front`.
func calculateHeightWith(width: CGFloat, font: UIFont)-> CGFloat {
let attr = [NSAttributedString.Key.font: font]
let maxSize: CGSize = CGSize(width: width, height: CGFloat(MAXFLOAT))
let option = NSStringDrawingOptions.usesLineFragmentOrigin
return self.boundingRect(with: (maxSize), options: option, attributes: attr, context: nil).size.height
}
}
================================================
FILE: AppStoreDemo/Extension/UIColor+Extension.swift
================================================
//
// UIColor+Extension.swift
// AppStoreDemo
//
// Created by Allen long on 2019/8/5.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
extension UIColor {
convenience init(r: CGFloat, g: CGFloat, b: CGFloat, alpha: CGFloat = 1.0) {
self.init(red: r/255.0, green: g/255.0, blue: b/255.0, alpha: alpha)
}
}
================================================
FILE: AppStoreDemo/Extension/UITableView+Extension.swift
================================================
//
// UITableView+Extension.swift
// AppStoreDemo
//
// Created by Allen long on 2019/8/5.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
extension UITableView {
// 注册有nib的cell
func ut_registerNibCell<T>(_ cellType: T.Type) where T: UITableViewCell {
let nib = UINib(nibName: "\(cellType)", bundle: nil)
let identifier = "\(cellType)"
register(nib, forCellReuseIdentifier: identifier)
}
// 注册无nib的cell
func ut_registerClassCell<T>(_ cellType: T.Type) where T: UITableViewCell {
let identifier = "\(cellType)"
register(cellType, forCellReuseIdentifier: identifier)
}
// 从缓存池池出队已经存在的 cell
func ut_dequeueReusable<T: UITableViewCell>(_ cell: T.Type, for indexPath: IndexPath) -> T {
let cell = dequeueReusableCell(withIdentifier: "\(T.self)", for: indexPath) as! T
return cell
}
// 注册有nib的headerFooterView
func ut_registerNibHeaderFooterView<T>(_ viewType: T.Type) where T: UITableViewHeaderFooterView {
let nib = UINib(nibName: "\(viewType)", bundle: nil)
let identifier = "\(viewType)"
register(nib, forHeaderFooterViewReuseIdentifier: identifier)
}
// 注册无nib的headerFooterView
func ut_registerClassHeaderFooterView<T>(_ viewType: T.Type) where T: UITableViewHeaderFooterView {
let identifier = "\(viewType)"
register(viewType, forHeaderFooterViewReuseIdentifier: identifier)
}
// 从缓存池里取出已注册的headerFooterView
func ut_dequeueReusableHeaderFooterView<T: UITableViewHeaderFooterView>(_ view: T.Type) -> T {
let headerFooterView = dequeueReusableHeaderFooterView(withIdentifier: "\(T.self)") as! T
return headerFooterView
}
}
extension UICollectionView {
// 注册有nib的cell
func ut_registerNibCell<T>(_ cellType: T.Type) where T: UICollectionViewCell {
let nib = UINib(nibName: "\(cellType)", bundle: nil)
let identifier = "\(cellType)"
register(nib, forCellWithReuseIdentifier: identifier)
}
// 注册无nib的cell
func ut_registerClassCell<T>(_ cellType: T.Type) where T: UICollectionViewCell {
let identifier = "\(cellType)"
register(cellType, forCellWithReuseIdentifier: identifier)
}
// 从缓存池池出队已经存在的 cell
func ut_dequeueReusable<T: UICollectionViewCell>(_ cell: T.Type, for indexPath: IndexPath) -> T {
let cell = dequeueReusableCell(withReuseIdentifier: "\(T.self)", for: indexPath) as! T
return cell
}
}
================================================
FILE: AppStoreDemo/Extension/UIView+Extension.swift
================================================
//
// UIView+Extension.swift
// AppStoreDemo
//
// Created by Allen long on 2019/8/2.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
protocol NibLoadable {}
extension NibLoadable where Self: UIView {
static func loadViewFromNib() -> Self {
return Bundle.main.loadNibNamed("\(self)", owner: nil, options: nil)?.first as! Self
}
}
extension UIView {
// Constrain 4 edges of `self` to specified `view`.
func edges(to view: UIView, top: CGFloat=0, left: CGFloat=0, bottom: CGFloat=0, right: CGFloat=0) {
NSLayoutConstraint.activate([
self.leftAnchor.constraint(equalTo: view.leftAnchor, constant: left),
self.rightAnchor.constraint(equalTo: view.rightAnchor, constant: right),
self.topAnchor.constraint(equalTo: view.topAnchor, constant: top),
self.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: bottom)
])
}
// Set view's cornerRadius
@IBInspectable var cornerRadius: CGFloat {
get {
return layer.cornerRadius
}
set {
layer.cornerRadius = newValue
layer.masksToBounds = newValue > 0
}
}
@IBInspectable var borderWidth: CGFloat {
get {
return layer.borderWidth
}
set {
layer.borderWidth = newValue
}
}
@IBInspectable var borderColor: UIColor {
get {
return UIColor(cgColor: layer.borderColor ?? UIColor.black.cgColor)
}
set {
layer.borderColor = newValue.cgColor
}
}
}
================================================
FILE: AppStoreDemo/Extension/UIViewController+Extension.swift
================================================
//
// UIViewController+Extension.swift
// AppStoreDemo
//
// Created by Erwin on 2019/8/4.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
extension UIViewController {
private struct associateKeys {
static var iconButtonKey = "UIViewController+Extension+iconButton"
}
// We use `runtime` to add a iconButton for every UIViewController we want
var iconButton: UIButton? {
get {
return objc_getAssociatedObject(self, &associateKeys.iconButtonKey) as? UIButton
}
set {
objc_setAssociatedObject(self, &associateKeys.iconButtonKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
func setNavigationBarBottomLineHidden(_ isHidden: Bool) {
navigationController?.navigationBar.setValue(isHidden, forKey: "hidesShadow")
}
/** Add icon button on navigationBar.
We can not use `UIBarButtonItem` here for adding a button on navigationBar,
because it will cause an unsuitable layout.
So I use a custom button instead.
*/
func addIconButtonOnNavigationBar() {
guard let navController = navigationController else { return }
guard let classType = NSClassFromString("_UINavigationBarLargeTitleView") else { return }
if iconButton == nil {
iconButton = createIconButtonForNavigationBar()
}
for subView in navController.navigationBar.subviews {
if subView.isKind(of: classType) {
subView.addSubview(iconButton!)
guard let largeTitleLabel = subView.subviews.first as? UILabel else { return }
iconButton!.translatesAutoresizingMaskIntoConstraints = false
iconButton!.trailingAnchor.constraint(equalTo: subView.trailingAnchor, constant: -25).isActive = true
iconButton!.centerYAnchor.constraint(equalTo: largeTitleLabel.centerYAnchor, constant: -5).isActive = true
iconButton!.widthAnchor.constraint(equalToConstant: 35).isActive = true
iconButton!.heightAnchor.constraint(equalToConstant: 35).isActive = true
}
}
}
// change navigationBar backgroundColor for iOS 13
func adjustNavigationForiOS13() {
if #available(iOS 13.0, *) {
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithOpaqueBackground()
navBarAppearance.backgroundColor = .white
navBarAppearance.shadowColor = nil
navigationController?.navigationBar.standardAppearance = navBarAppearance
navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
}
}
// creat a button for navigationBar
private func createIconButtonForNavigationBar()-> UIButton {
let btn = UIButton()
btn.setImage(#imageLiteral(resourceName: "demo_icon"), for: .normal)
btn.setImage(#imageLiteral(resourceName: "demo_icon"), for: .highlighted)
btn.translatesAutoresizingMaskIntoConstraints = false
btn.layer.borderColor = GlobalConstants.iconBorderColor
btn.layer.borderWidth = GlobalConstants.iconBorderWidth
btn.layer.cornerRadius = GlobalConstants.iconCornerRadius
btn.addTarget(self, action: #selector(presentUserTableViewController), for: .touchUpInside)
return btn
}
@objc func presentUserTableViewController() {
let navController = UIStoryboard(name: "User", bundle: nil).instantiateViewController(withIdentifier: "UserNavigationControllerID")
present(navController, animated: true, completion: nil)
}
}
extension UIResponder {
func setStatusBarColor(_ color: UIColor) {
if #available(iOS 13.0, *) {
let tag = 38482
let keyWindow = UIApplication.shared.windows.filter {$0.isKeyWindow}.first
if let statusBar = keyWindow?.viewWithTag(tag) {
statusBar.backgroundColor = color
} else {
guard let statusBarFrame = keyWindow?.windowScene?.statusBarManager?.statusBarFrame else { return }
let statusBarView = UIView(frame: statusBarFrame)
statusBarView.tag = tag
statusBarView.backgroundColor = color
keyWindow?.addSubview(statusBarView)
}
} else if let statusBar = UIApplication.shared.value(forKeyPath: "statusBarWindow.statusBar") as? UIView {
statusBar.backgroundColor = color
}
}
}
================================================
FILE: AppStoreDemo/Game/Controller/DetailViewController.swift
================================================
//
// DetailViewController.swift
// AppStoreDemo
//
// Created by Allen long on 2019/8/7.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
fileprivate let navigationViewH: CGFloat = statusBarH + navigationBarH
fileprivate let tableViewTopInset: CGFloat = 200
fileprivate let topImageViewHeight: CGFloat = 288
fileprivate let originalContentOffSetY: CGFloat = tableViewTopInset + statusBarH
fileprivate let alphaChangeProgress: CGFloat = (hasTopNotch() ? 112 : 84)
class DetailViewController: UIViewController {
lazy var navigationView: DetailNavigationView = {
let it = DetailNavigationView()
it.frame = CGRect(x: 0, y: 0, width: kScreenW, height: navigationViewH)
return it
}()
lazy var tableView: UITableView = {
let it = UITableView()
it.frame = CGRect(x: 0, y: -statusBarH, width: kScreenW, height: kScreenH + statusBarH)
it.backgroundColor = .white
it.delegate = self
it.dataSource = self
it.contentInset = UIEdgeInsets(top: tableViewTopInset, left: 0, bottom: 0, right: 0)
it.separatorInset = UIEdgeInsets(top: 0, left: GlobalConstants.leftMargin, bottom: 0, right: GlobalConstants.leftMargin)
it.ut_registerNibCell(DetailTopInfoCell.self)
it.ut_registerNibCell(DetailNewFeaturesCell.self)
it.ut_registerClassCell(DetailPreviewCell.self)
it.ut_registerClassCell(DetailInformationCell.self)
return it
}()
lazy var topImageView: UIImageView = {
let it = UIImageView()
it.image = #imageLiteral(resourceName: "cover_detail")
it.contentMode = .scaleAspectFill
it.frame = CGRect(x: 0, y: -(topImageViewHeight) , width: kScreenW, height: topImageViewHeight)
it.layer.masksToBounds = true
return it
}()
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.interactivePopGestureRecognizer?.delegate = nil
tableView.addSubview(topImageView)
view.addSubview(tableView)
view.addSubview(navigationView)
navigationView.goBackClosure = { [weak self] in
guard let StrongSelf = self else { return }
StrongSelf.navigationController?.popViewController(animated: true)
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.setNavigationBarHidden(true, animated: true)
setStatusBarColor(UIColor.white.withAlphaComponent(0))
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
navigationController?.setNavigationBarHidden(false, animated: true)
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
setStatusBarColor(.white)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
navigationController?.interactivePopGestureRecognizer?.isEnabled = true
}
}
extension DetailViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch indexPath.row {
case 0:
let cell = tableView.ut_dequeueReusable(DetailTopInfoCell.self, for: indexPath)
cell.selectionStyle = .none
return cell
case 1:
let cell = tableView.ut_dequeueReusable(DetailNewFeaturesCell.self, for: indexPath)
cell.selectionStyle = .none
return cell
case 2:
let cell = tableView.ut_dequeueReusable(DetailPreviewCell.self, for: indexPath)
cell.selectionStyle = .none
return cell
case 3:
let cell = tableView.ut_dequeueReusable(DetailInformationCell.self, for: indexPath)
cell.selectionStyle = .none
return cell
default:
return UITableViewCell()
}
}
}
extension DetailViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
switch indexPath.row {
case 0:
return 230
case 1:
return 168
case 2:
return 227
case 3:
return 520
default:
return 0
}
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
var offSetY = scrollView.contentOffset.y
// change topImageView frame
if offSetY < -originalContentOffSetY {
topImageView.frame.origin.y = offSetY - (hasTopNotch() ? 44 : 64)
topImageView.frame.size.height = -(offSetY - (hasTopNotch() ? 44 : 64))
}
// change navigationView backgroundColor and goBackBtn color
//deal with offsetY to make sure alpha from 0 to 1
if offSetY > -(originalContentOffSetY - alphaChangeProgress) {
offSetY = -(originalContentOffSetY - alphaChangeProgress)
} else if offSetY < -originalContentOffSetY {
offSetY = -originalContentOffSetY
}
let calculateY = offSetY + originalContentOffSetY
navigationView.backgroundColor = UIColor.white.withAlphaComponent(calculateY/alphaChangeProgress)
// values of targetRed and targetGreen are from GlobalConstants.textBlueColor
// blue is still 255.0, so we do not neet to change it
let targetRed: CGFloat = 0
let targetGreen: CGFloat = 122
let color = UIColor(red: (255 - ((255.0 - targetRed)/alphaChangeProgress) * calculateY) / 255.0, green: (255 - ((255.0 - targetGreen)/alphaChangeProgress) * calculateY) / 255.0, blue: 255.0/255.0, alpha: 1)
navigationView.goBackBtn.setTitleColor(color, for: .normal)
navigationView.goBackBtn.tintColor = color
}
}
================================================
FILE: AppStoreDemo/Game/Controller/DownloadPresentationController.swift
================================================
//
// DownloadPresentationController.swift
// AppStoreDemo
//
// Created by Allen long on 2019/9/5.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
class DownloadPresentationController: UIPresentationController {
private lazy var dimmingView: UIView = {
let view = UIView()
view.backgroundColor = UIColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.7)
view.alpha = 0
return view
}()
override var shouldRemovePresentersView: Bool {
return false
}
override func presentationTransitionWillBegin() {
guard
let containerView = containerView,
let presentedView = presentedView
else {
return
}
dimmingView.frame = containerView.bounds
containerView.addSubview(dimmingView)
containerView.addSubview(presentedView)
presentingViewController.beginAppearanceTransition(false, animated: false)
presentedViewController.transitionCoordinator!.animate(alongsideTransition: { (ctx) in
self.dimmingView.alpha = 1
}) { (ctx) in }
}
override func presentationTransitionDidEnd(_ completed: Bool) {
presentingViewController.endAppearanceTransition()
}
override func dismissalTransitionWillBegin() {
presentingViewController.beginAppearanceTransition(true, animated: true)
presentedViewController.transitionCoordinator!.animate(alongsideTransition: { (ctx) in
self.dimmingView.alpha = 0.0
}, completion: nil)
}
override func dismissalTransitionDidEnd(_ completed: Bool) {
presentingViewController.endAppearanceTransition()
if completed {
dimmingView.removeFromSuperview()
}
}
}
================================================
FILE: AppStoreDemo/Game/Controller/DownloadViewController.swift
================================================
//
// DownloadViewController.swift
// AppStoreDemo
//
// Created by Allen long on 2019/9/5.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
class DownloadViewController: UIViewController {
var model: GameTopicModel?
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nil, bundle: nil)
modalPresentationStyle = .custom
transitioningDelegate = self
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
setStatusBarColor(UIColor.white.withAlphaComponent(0))
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
setStatusBarColor(.white)
}
override func viewDidLoad() {
super.viewDidLoad()
if let model = model {
bottomView.model = model
}
view.addSubview(bottomView)
if #available(iOS 13.0, *) {
//在iOS13上,获取keywindow后,并不能将clickView加到屏幕最上方,因此将它加到view上。但这时的弹出动画就与系统不一样了。
//如果有知道如何做的朋友,麻烦给我提个issue,谢了
view.addSubview(clickView)
} else {
keyWindow.addSubview(clickView)
}
}
private lazy var bottomView: DownloadBottomView = {
let view = DownloadBottomView.loadViewFromNib()
let height = 260 + tabbarExtraH
view.frame = CGRect(x: 0, y: kScreenH - height, width: kScreenW, height: height)
view.delegate = self
return view
}()
lazy var clickView: DownloadClickView = {
let view = DownloadClickView.loadViewFromNib()
view.frame = CGRect(x: kScreenW, y: 168, width: GlobalConstants.doubleClickViewW, height: 110)
return view
}()
}
extension DownloadViewController: DownloadBottomViewDelegate {
func downloadBottomViewDidClickCancel(_ bottomView: DownloadBottomView) {
dismiss(animated: true, completion: nil)
}
}
extension DownloadViewController: UIViewControllerTransitioningDelegate {
func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
if presented == self {
return DownloadPresentationController(presentedViewController: presented, presenting: presenting)
}
return nil
}
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return DownloadTransitioning(isPresenting: true, transitionDuration: 0.3)
}
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return DownloadTransitioning(isPresenting: false, transitionDuration: 0.3)
}
}
================================================
FILE: AppStoreDemo/Game/Controller/GameTableViewController.swift
================================================
//
// GameTableViewController.swift
// AppStoreDemo
//
// Created by Allen long on 2019/8/6.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
class GameTableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
adjustNavigationForiOS13()
setNavigationBarBottomLineHidden(true)
addIconButtonOnNavigationBar()
registerCells()
}
private func registerCells() {
tableView.ut_registerClassCell(GameRecommandTableViewCell.self)
tableView.ut_registerClassCell(GameTopicTableViewCell.self)
tableView.ut_registerClassCell(GameLinkTableViewCell.self)
}
private func pushToDetailController() {
navigationController?.pushViewController(DetailViewController(), animated: true)
}
// MARK: - Table view data source and delegate
override func numberOfSections(in tableView: UITableView) -> Int {
return 3
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.section == 0 {
return GlobalConstants.recommandHeight
} else if indexPath.section == 1 {
return GlobalConstants.topicHeight
} else if indexPath.section == 2 {
return GlobalConstants.linkHeight
}
return 0
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
if section == 0 || section == 1 || section == 2 {
return 1
}
return 0
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cell = tableView.ut_dequeueReusable(GameRecommandTableViewCell.self, for: indexPath)
cell.detailClosure = {
self.pushToDetailController()
}
return cell
} else if indexPath.section == 1 {
let cell = tableView.ut_dequeueReusable(GameTopicTableViewCell.self, for: indexPath)
cell.detailClosure = {
self.pushToDetailController()
}
cell.downloadClosure = { model in
let vc = DownloadViewController()
vc.model = model
self.present(vc, animated: true, completion: nil)
}
return cell
} else if indexPath.section == 2 {
let cell = tableView.ut_dequeueReusable(GameLinkTableViewCell.self, for: indexPath)
return cell
}
return UITableViewCell()
}
override func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView.contentOffset.y > 0 {
setNavigationBarBottomLineHidden(false)
} else {
setNavigationBarBottomLineHidden(true)
}
}
}
================================================
FILE: AppStoreDemo/Game/Model/DownloadTransitioning.swift
================================================
//
// DownloadTransitioning.swift
// AppStoreDemo
//
// Created by Allen long on 2019/9/5.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
class DownloadTransitioning: NSObject {
let isPresenting: Bool
let transitionDuration: TimeInterval
//a height make animation more smoother when dismissing
let dismissHeight: CGFloat?
init(isPresenting: Bool, transitionDuration: TimeInterval, dismissHeight: CGFloat? = nil) {
self.isPresenting = isPresenting
self.transitionDuration = transitionDuration
self.dismissHeight = dismissHeight
super.init()
}
}
extension DownloadTransitioning: UIViewControllerAnimatedTransitioning {
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return transitionDuration
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
if isPresenting {
animationForPresent(using: transitionContext)
} else {
animationForDismiss(using: transitionContext)
}
}
}
// MARK: - Helper
extension DownloadTransitioning {
private func animationForPresent(using transitionContext: UIViewControllerContextTransitioning) {
guard let presentedVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to) as? DownloadViewController else { return }
guard let presentedView = transitionContext.view(forKey: UITransitionContextViewKey.to) else { return }
let containerView = transitionContext.containerView
// Position the presented view off the top of the container view
presentedView.frame = transitionContext.finalFrame(for: presentedVC)
presentedView.center.y += containerView.bounds.size.height
containerView.addSubview(presentedView)
UIView.animate(withDuration: transitionDuration, animations: {
presentedView.center.y -= containerView.bounds.size.height
presentedVC.clickView.frame.origin.x -= clickViewShowH
}) { (completed) in
transitionContext.completeTransition(completed)
}
delay(0.5) {
presentedVC.clickView.startMoving()
}
}
private func animationForDismiss(using transitionContext: UIViewControllerContextTransitioning) {
guard let presentedVC = transitionContext.viewController(forKey: .from) as? DownloadViewController else { return }
guard let presentedView = transitionContext.view(forKey: UITransitionContextViewKey.from) else { return }
let containerView = transitionContext.containerView
UIView.animate(withDuration: transitionDuration, animations: {
if let height = self.dismissHeight {
presentedView.center.y += height
} else {
presentedView.center.y += containerView.bounds.size.height
}
presentedVC.clickView.frame.origin.x += clickViewShowH
}) { (completed) in
transitionContext.completeTransition(completed)
presentedVC.clickView.removeFromSuperview()
}
presentedVC.clickView.endMoving()
}
}
fileprivate let clickViewShowH: CGFloat = GlobalConstants.doubleClickViewW - GlobalConstants.clickBarWidth
================================================
FILE: AppStoreDemo/Game/Model/GameRecommandModel.swift
================================================
//
// GameRecommandModel.swift
// AppStoreDemo
//
// Created by Allen long on 2019/8/6.
// Copyright © 2019 Utimes. All rights reserved.
//
import Foundation
struct GameRecommandModel {
let feature: String
let name: String
let desc: String
let coverImageName: String
}
================================================
FILE: AppStoreDemo/Game/Model/GameTopicModel.swift
================================================
//
// GameTopicModel.swift
// AppStoreDemo
//
// Created by Allen long on 2019/8/6.
// Copyright © 2019 Utimes. All rights reserved.
//
import Foundation
struct GameTopicModel {
let name: String
let desc: String
let iconImageName: String
}
================================================
FILE: AppStoreDemo/Game/View/Detail/DetailInfomationTableViewCell.swift
================================================
//
// DetailInfomationTableViewCell.swift
// AppStoreDemo
//
// Created by Allen long on 2019/8/9.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
class DetailInfomationTableViewCell: UITableViewCell {
let nameLabel = UILabel()
let contentLabel = UILabel()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupUI()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupUI() {
nameLabel.textColor = .lightGray
nameLabel.font = UIFont.systemFont(ofSize: 15)
nameLabel.textAlignment = .left
contentLabel.textColor = UIColor.black
contentLabel.font = UIFont.systemFont(ofSize: 15)
contentLabel.textAlignment = .right
nameLabel.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(nameLabel)
contentLabel.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(contentLabel)
nameLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true
nameLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20).isActive = true
contentLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true
contentLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -20).isActive = true
contentLabel.leadingAnchor.constraint(greaterThanOrEqualTo: nameLabel.trailingAnchor, constant: 30).isActive = true
nameLabel.setContentHuggingPriority(UILayoutPriority(rawValue: 252), for: .horizontal)
contentLabel.setContentCompressionResistancePriority(UILayoutPriority(749), for: .horizontal)
}
}
================================================
FILE: AppStoreDemo/Game/View/Detail/DetailInformationCell.swift
================================================
//
// DetailInformationCell.swift
// AppStoreDemo
//
// Created by Allen long on 2019/8/9.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
class DetailInformationCell: UITableViewCell {
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(headerView)
contentView.addSubview(tableView)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private lazy var headerView: CommonSectionHeaderView = {
let frame = CGRect(x: 0, y: 0, width: kScreenW, height: 52)
let it = CommonSectionHeaderView(frame: frame)
it.changeSectionTitle(with: "Information")
it.lineView.isHidden = true
return it
}()
private lazy var tableView: UITableView = {
let frame = CGRect(x: 0, y: self.headerView.frame.height, width: kScreenW, height: 400)
let it = UITableView(frame: frame)
it.separatorInset = UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 20)
it.dataSource = self
it.ut_registerClassCell(DetailInfomationTableViewCell.self)
it.rowHeight = 50
return it
}()
}
extension DetailInformationCell: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataSource.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.ut_dequeueReusable(DetailInfomationTableViewCell.self, for: indexPath)
cell.nameLabel.text = dataSource[indexPath.row].0
cell.contentLabel.text = dataSource[indexPath.row].1
cell.selectionStyle = .none
return cell
}
}
fileprivate let dataSource: [(String,String)] = [
("Seller", "Hangzhou NetEase Leihuo Technology Co., Ltd."),
("Size", "2.5GB"),
("Category", "Games: Strategy"),
("Compatibility", "Works on this iphone"),
("Languages", "Simplified Chinese"),
("Age Rating", "9+"),
("In-App Purchases", "Yes"),
("Copyright", "©1997-2019 网易公司版权所有")
]
================================================
FILE: AppStoreDemo/Game/View/Detail/DetailNavigationView.swift
================================================
//
// DetailNavigationView.swift
// AppStoreDemo
//
// Created by Allen long on 2019/8/7.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
class DetailNavigationView: UIView {
var goBackClosure: (()->())?
let goBackBtn = UIButton()
override init(frame: CGRect) {
super.init(frame: frame)
setupUI()
backgroundColor = UIColor.white.withAlphaComponent(0)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupUI() {
goBackBtn.setTitle("Games", for: .normal)
goBackBtn.setTitleColor(UIColor.white, for: .normal)
let image = UIImage(named: "navigation_back")?.withRenderingMode(.alwaysTemplate)
goBackBtn.setImage(image, for: .normal)
goBackBtn.tintColor = UIColor.white
goBackBtn.frame = CGRect(x: 5, y: statusBarH + 5, width: 80, height: 30)
goBackBtn.addTarget(self, action: #selector(goBackAction), for: .touchUpInside)
addSubview(goBackBtn)
}
@objc private func goBackAction() {
goBackClosure?()
}
}
================================================
FILE: AppStoreDemo/Game/View/Detail/DetailNewFeaturesCell.swift
================================================
//
// DetailNewFeaturesCell.swift
// AppStoreDemo
//
// Created by Allen long on 2019/8/8.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
class DetailNewFeaturesCell: UITableViewCell {
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
================================================
FILE: AppStoreDemo/Game/View/Detail/DetailNewFeaturesCell.xib
================================================
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" rowHeight="141" id="KGk-i7-Jjw" customClass="DetailNewFeaturesCell" customModule="AppStoreTodayDemo" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="311" height="141"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
<rect key="frame" x="0.0" y="0.0" width="311" height="140.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="What's News" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="WYL-Ra-05C">
<rect key="frame" x="20" y="14" width="129" height="22"/>
<constraints>
<constraint firstAttribute="height" constant="22" id="2A0-JI-vso"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="22"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Version 1.0.5" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ivW-Y5-4Qt">
<rect key="frame" x="20" y="51" width="87" height="15"/>
<constraints>
<constraint firstAttribute="height" constant="15" id="gFX-W4-du9"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Version History" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="c6v-Mp-5MT">
<rect key="frame" x="174" y="14.5" width="117" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.47843137250000001" blue="1" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="two days ago" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="0YL-Ny-Dnu">
<rect key="frame" x="200" y="49.5" width="91" height="18"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Here are more styles for playing. You can chose more than 2 characters for yourself. Just have a try!" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7GW-j5-owT">
<rect key="frame" x="20" y="80" width="271" height="40.5"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="0YL-Ny-Dnu" secondAttribute="trailing" constant="20" id="57D-GZ-Kl6"/>
<constraint firstItem="c6v-Mp-5MT" firstAttribute="centerY" secondItem="WYL-Ra-05C" secondAttribute="centerY" id="61Y-lb-r1s"/>
<constraint firstItem="7GW-j5-owT" firstAttribute="top" secondItem="ivW-Y5-4Qt" secondAttribute="bottom" constant="14" id="Imd-C3-ZnS"/>
<constraint firstItem="WYL-Ra-05C" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="20" id="Jxu-6Y-2oA"/>
<constraint firstItem="7GW-j5-owT" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="20" id="PAZ-JE-PXn"/>
<constraint firstItem="WYL-Ra-05C" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" constant="14" id="Qci-kQ-hmb"/>
<constraint firstAttribute="trailing" secondItem="7GW-j5-owT" secondAttribute="trailing" constant="20" id="Uld-nK-B0x"/>
<constraint firstItem="0YL-Ny-Dnu" firstAttribute="centerY" secondItem="ivW-Y5-4Qt" secondAttribute="centerY" id="XNq-iK-C6P"/>
<constraint firstItem="ivW-Y5-4Qt" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="20" id="dVj-S6-tbb"/>
<constraint firstAttribute="trailing" secondItem="c6v-Mp-5MT" secondAttribute="trailing" constant="20" id="jEw-fb-ryV"/>
<constraint firstAttribute="bottom" secondItem="7GW-j5-owT" secondAttribute="bottom" constant="20" id="mFv-Cb-RYD"/>
<constraint firstItem="ivW-Y5-4Qt" firstAttribute="top" secondItem="WYL-Ra-05C" secondAttribute="bottom" constant="15" id="v00-I7-hCn"/>
</constraints>
</tableViewCellContentView>
<viewLayoutGuide key="safeArea" id="njF-e1-oar"/>
<point key="canvasLocation" x="-254" y="79"/>
</tableViewCell>
</objects>
</document>
================================================
FILE: AppStoreDemo/Game/View/Detail/DetailPreviewCell.swift
================================================
//
// DetailPreviewCell.swift
// AppStoreDemo
//
// Created by Allen long on 2019/8/8.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
class DetailPreviewCell: UITableViewCell {
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupUI()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupUI() {
contentView.addSubview(headerView)
contentView.addSubview(collectionView)
}
private lazy var headerView: CommonSectionHeaderView = {
let frame = CGRect(x: 0, y: 0, width: kScreenW, height: 42)
let it = CommonSectionHeaderView(frame: frame)
it.changeSectionTitle(with: "Review")
it.lineView.isHidden = true
return it
}()
private lazy var collectionView: DetailPreviewCollectionView = {
let itemSize = CGSize(width: kScreenW - 2 * GlobalConstants.leftMargin, height: GlobalConstants.detailPreviewImageH)
let frame = CGRect(x: 0, y: 52, width: kScreenW, height: GlobalConstants.detailPreviewImageH)
let layout = CommonCollectionFlowLayout(itemSize: itemSize)
let collectionView = DetailPreviewCollectionView(frame: frame, collectionViewLayout: layout)
collectionView.dataSource = self
collectionView.delegate = self
return collectionView
}()
}
extension DetailPreviewCell: UICollectionViewDataSource,UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return dataSource.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.ut_dequeueReusable(DetailPreviewCollectionViewCell.self, for: indexPath)
cell.coverImageView.image = UIImage(named: dataSource[indexPath.item])
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
}
}
fileprivate let dataSource: [String] = [
"cover_detail1",
"cover_detail2",
"cover_detail"
]
================================================
FILE: AppStoreDemo/Game/View/Detail/DetailPreviewCollectionView.swift
================================================
//
// DetailPreviewCollectionView.swift
// AppStoreDemo
//
// Created by Allen long on 2019/8/8.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
class DetailPreviewCollectionView: UICollectionView {
override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
super.init(frame: frame, collectionViewLayout: layout)
config()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func config() {
backgroundColor = .white
decelerationRate = UIScrollView.DecelerationRate.fast
ut_registerClassCell(DetailPreviewCollectionViewCell.self)
showsHorizontalScrollIndicator = false
}
}
================================================
FILE: AppStoreDemo/Game/View/Detail/DetailPreviewCollectionViewCell.swift
================================================
//
// DetailPreviewCollectionViewCell.swift
// AppStoreDemo
//
// Created by Allen long on 2019/8/8.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
class DetailPreviewCollectionViewCell: UICollectionViewCell {
let coverImageView = UIImageView()
override init(frame: CGRect) {
super.init(frame: frame)
coverImageView.frame = CGRect(x: 0, y: 0, width: self.frame.width, height: GlobalConstants.detailPreviewImageH)
coverImageView.cornerRadius = 14.0
coverImageView.contentMode = .scaleAspectFill
contentView.addSubview(coverImageView)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
================================================
FILE: AppStoreDemo/Game/View/Detail/DetailTopInfoCell.swift
================================================
//
// DetailTopInfoCell.swift
// AppStoreDemo
//
// Created by Allen long on 2019/8/8.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
class DetailTopInfoCell: UITableViewCell {
override func awakeFromNib() {
super.awakeFromNib()
setupUI()
}
private func setupUI() {
for index in 0...3 {
let star = StarView(frame: CGRect(x: index * (15 + 3), y: 0, width: 15, height: 15))
starBackView.addSubview(star)
}
}
@IBOutlet weak var starBackView: UIView!
}
================================================
FILE: AppStoreDemo/Game/View/Detail/DetailTopInfoCell.xib
================================================
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" rowHeight="226" id="KGk-i7-Jjw" customClass="DetailTopInfoCell" customModule="AppStoreTodayDemo" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="352" height="226"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
<rect key="frame" x="0.0" y="0.0" width="352" height="225.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="logo_game" translatesAutoresizingMaskIntoConstraints="NO" id="tiI-sU-Z6o">
<rect key="frame" x="20" y="20" width="118" height="118"/>
<constraints>
<constraint firstAttribute="width" constant="118" id="sNK-yB-9Bc"/>
<constraint firstAttribute="height" constant="118" id="uH5-sj-TUo"/>
</constraints>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
<real key="value" value="26"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Onmyoji " textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="d15-nB-2Mo">
<rect key="frame" x="158" y="30" width="93" height="25"/>
<constraints>
<constraint firstAttribute="height" constant="25" id="N5f-Md-Sbm"/>
</constraints>
<fontDescription key="fontDescription" name="PingFangSC-Medium" family="PingFang SC" pointSize="22"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="The best game" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="G2w-No-SZn">
<rect key="frame" x="158" y="61" width="105" height="18"/>
<constraints>
<constraint firstAttribute="height" constant="18" id="AOh-ES-23M"/>
</constraints>
<fontDescription key="fontDescription" name="PingFangSC-Regular" family="PingFang SC" pointSize="15"/>
<color key="textColor" red="0.60392156862745094" green="0.60271537303924561" blue="0.60271537303924561" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="BEu-g1-DnR">
<rect key="frame" x="158" y="108" width="30" height="30"/>
<constraints>
<constraint firstAttribute="height" constant="30" id="4Wk-WY-NHU"/>
<constraint firstAttribute="width" constant="30" id="Ojo-Su-b9f"/>
</constraints>
<state key="normal" image="detail_download"/>
</button>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="FHb-ar-fAV">
<rect key="frame" x="20" y="173" width="90" height="15"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="15" id="3kI-7L-0C2"/>
<constraint firstAttribute="width" constant="90" id="52I-tz-OfJ"/>
</constraints>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="4.0, 250rateings" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="F85-Ay-7P0">
<rect key="frame" x="20" y="198" width="95.5" height="14"/>
<constraints>
<constraint firstAttribute="height" constant="14" id="meS-bI-B2v"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="12"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="9+" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Svi-qZ-ImG">
<rect key="frame" x="306.5" y="166" width="28" height="22"/>
<constraints>
<constraint firstAttribute="height" constant="22" id="6F0-T3-qKz"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="22"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Age" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fPj-UT-IDK">
<rect key="frame" x="309" y="198" width="23" height="14"/>
<constraints>
<constraint firstAttribute="height" constant="14" id="AsL-9R-LdB"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="12"/>
<color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="strategy" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6Bz-mf-KEg">
<rect key="frame" x="215.5" y="198" width="48.5" height="14"/>
<constraints>
<constraint firstAttribute="height" constant="14" id="rGS-XF-rkm"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="12"/>
<color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="#31" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dOx-33-HFw">
<rect key="frame" x="221" y="165.5" width="38" height="22"/>
<constraints>
<constraint firstAttribute="height" constant="22" id="CAC-bT-V3S"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="22"/>
<color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="UGM-oL-VZP">
<rect key="frame" x="302" y="108" width="30" height="30"/>
<constraints>
<constraint firstAttribute="width" constant="30" id="Ke9-FR-rjR"/>
<constraint firstAttribute="height" constant="30" id="SYW-hY-5G7"/>
</constraints>
<state key="normal" image="detail_more"/>
</button>
</subviews>
<constraints>
<constraint firstItem="fPj-UT-IDK" firstAttribute="centerY" secondItem="F85-Ay-7P0" secondAttribute="centerY" id="1hm-iv-oSq"/>
<constraint firstItem="d15-nB-2Mo" firstAttribute="leading" secondItem="tiI-sU-Z6o" secondAttribute="trailing" constant="20" id="3Gy-1R-wMX"/>
<constraint firstItem="6Bz-mf-KEg" firstAttribute="centerX" secondItem="dOx-33-HFw" secondAttribute="centerX" id="8Yq-yi-8Qf"/>
<constraint firstItem="6Bz-mf-KEg" firstAttribute="centerY" secondItem="F85-Ay-7P0" secondAttribute="centerY" id="CiH-2C-9n5"/>
<constraint firstItem="BEu-g1-DnR" firstAttribute="leading" secondItem="tiI-sU-Z6o" secondAttribute="trailing" constant="20" id="DFI-0o-8D9"/>
<constraint firstItem="UGM-oL-VZP" firstAttribute="centerY" secondItem="BEu-g1-DnR" secondAttribute="centerY" id="KFz-oV-X14"/>
<constraint firstItem="tiI-sU-Z6o" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="20" id="NL2-2w-P2g"/>
<constraint firstItem="G2w-No-SZn" firstAttribute="leading" secondItem="tiI-sU-Z6o" secondAttribute="trailing" constant="20" id="Sum-cp-nHl"/>
<constraint firstItem="FHb-ar-fAV" firstAttribute="top" secondItem="tiI-sU-Z6o" secondAttribute="bottom" constant="35" id="TIn-bc-cK7"/>
<constraint firstItem="fPj-UT-IDK" firstAttribute="top" secondItem="Svi-qZ-ImG" secondAttribute="bottom" constant="10" id="Z5t-sB-Mms"/>
<constraint firstAttribute="trailing" secondItem="UGM-oL-VZP" secondAttribute="trailing" constant="20" id="bUf-oy-TTg"/>
<constraint firstAttribute="trailing" secondItem="fPj-UT-IDK" secondAttribute="trailing" constant="20" id="bnt-5w-p6N"/>
<constraint firstItem="BEu-g1-DnR" firstAttribute="bottom" secondItem="tiI-sU-Z6o" secondAttribute="bottom" id="cIf-jj-QLj"/>
<constraint firstItem="FHb-ar-fAV" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="20" id="eaO-Jm-qR9"/>
<constraint firstItem="G2w-No-SZn" firstAttribute="top" secondItem="d15-nB-2Mo" secondAttribute="bottom" constant="6" id="gUB-jJ-4pw"/>
<constraint firstItem="Svi-qZ-ImG" firstAttribute="centerX" secondItem="fPj-UT-IDK" secondAttribute="centerX" id="iRi-GX-mLB"/>
<constraint firstItem="fPj-UT-IDK" firstAttribute="leading" secondItem="6Bz-mf-KEg" secondAttribute="trailing" constant="45" id="ijW-JX-A80"/>
<constraint firstItem="tiI-sU-Z6o" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" constant="20" id="rTB-35-R9r"/>
<constraint firstItem="F85-Ay-7P0" firstAttribute="top" secondItem="FHb-ar-fAV" secondAttribute="bottom" constant="10" id="s7Q-ox-TxJ"/>
<constraint firstItem="F85-Ay-7P0" firstAttribute="leading" secondItem="FHb-ar-fAV" secondAttribute="leading" id="uAC-vI-p2v"/>
<constraint firstItem="d15-nB-2Mo" firstAttribute="top" secondItem="tiI-sU-Z6o" secondAttribute="top" constant="10" id="vve-h4-9wJ"/>
<constraint firstItem="6Bz-mf-KEg" firstAttribute="top" secondItem="dOx-33-HFw" secondAttribute="bottom" constant="10.5" id="y6m-oN-bsI"/>
</constraints>
</tableViewCellContentView>
<viewLayoutGuide key="safeArea" id="njF-e1-oar"/>
<connections>
<outlet property="starBackView" destination="FHb-ar-fAV" id="B2I-BD-jDX"/>
</connections>
<point key="canvasLocation" x="95.652173913043484" y="12.723214285714285"/>
</tableViewCell>
</objects>
<resources>
<image name="detail_download" width="30" height="30"/>
<image name="detail_more" width="30" height="30"/>
<image name="logo_game" width="800" height="800"/>
</resources>
</document>
================================================
FILE: AppStoreDemo/Game/View/Download/DownloadBottomView.swift
================================================
//
// DownloadBottomView.swift
// AppStoreDemo
//
// Created by Allen long on 2019/9/5.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
protocol DownloadBottomViewDelegate: class {
func downloadBottomViewDidClickCancel(_ bottomView: DownloadBottomView)
}
class DownloadBottomView: UIView,NibLoadable {
weak var delegate: DownloadBottomViewDelegate?
@IBAction func cancelAction(_ sender: UIButton) {
delegate?.downloadBottomViewDidClickCancel(self)
}
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var descLabel: UILabel!
@IBOutlet weak var iconImageView: UIImageView!
var model: GameTopicModel! {
didSet {
nameLabel.text = model.name
descLabel.text = model.desc
iconImageView.image = UIImage(named: model.iconImageName)
}
}
}
================================================
FILE: AppStoreDemo/Game/View/Download/DownloadBottomView.xib
================================================
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="DownloadBottomView" customModule="AppStoreDemo" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="340" height="287"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="App Store" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="87E-8y-Hmq">
<rect key="frame" x="16" y="11" width="81" height="24"/>
<fontDescription key="fontDescription" name="PingFangSC-Medium" family="PingFang SC" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="DN7-AT-k3m">
<rect key="frame" x="272" y="7" width="52" height="32"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="16"/>
<state key="normal" title="Cancel"/>
<connections>
<action selector="cancelAction:" destination="iN0-l3-epB" eventType="touchUpInside" id="vW2-jR-ifX"/>
</connections>
</button>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Kxr-1J-Ugh">
<rect key="frame" x="0.0" y="45" width="340" height="0.5"/>
<color key="backgroundColor" red="0.55686274509803924" green="0.55686274509803924" blue="0.5725490196078431" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="height" constant="0.69999999999999996" id="t9G-5S-avS"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="yAp-G7-ISi">
<rect key="frame" x="16" y="120.5" width="324" height="0.5"/>
<color key="backgroundColor" red="0.55686274509803924" green="0.55686274509803924" blue="0.5725490196078431" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="height" constant="0.29999999999999999" id="5pu-1N-dxz"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="gm0-EC-Lnz">
<rect key="frame" x="16" y="166" width="324" height="0.5"/>
<color key="backgroundColor" red="0.5568627451" green="0.5568627451" blue="0.57254901960000004" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="height" constant="0.29999999999999999" id="MC7-a8-4we"/>
</constraints>
</view>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="RXj-2n-vDf">
<rect key="frame" x="55" y="63.5" width="40" height="40"/>
<constraints>
<constraint firstAttribute="width" constant="40" id="FRC-nN-BHi"/>
<constraint firstAttribute="height" constant="40" id="Vvt-rT-lHA"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="iUb-N3-zJQ">
<rect key="frame" x="111" y="58.5" width="39.5" height="17"/>
<constraints>
<constraint firstAttribute="height" constant="17" id="8S8-JH-31x"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="f6P-zA-4Z6">
<rect key="frame" x="111" y="75.5" width="39.5" height="17"/>
<constraints>
<constraint firstAttribute="height" constant="17" id="Heu-z5-cbp"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" red="0.5568627451" green="0.5568627451" blue="0.57254901960000004" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="OFFERS IN-APP PURCHASES" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="oaH-fj-5IL">
<rect key="frame" x="111" y="92.5" width="214" height="17"/>
<constraints>
<constraint firstAttribute="height" constant="17" id="R8B-GB-78L"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" red="0.5568627451" green="0.5568627451" blue="0.57254901960000004" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="ACCOUNT" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="VyH-tv-SSg">
<rect key="frame" x="31" y="135" width="64" height="17"/>
<constraints>
<constraint firstAttribute="height" constant="17" id="fXZ-yf-qBo"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="13"/>
<color key="textColor" red="0.5568627451" green="0.5568627451" blue="0.57254901960000004" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="hello@qq.com" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="JCZ-Gk-LId">
<rect key="frame" x="111" y="135" width="103.5" height="17"/>
<constraints>
<constraint firstAttribute="height" constant="17" id="qFg-3Q-y0h"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="demo_icon" translatesAutoresizingMaskIntoConstraints="NO" id="T3T-T0-BjE">
<rect key="frame" x="148" y="186.5" width="44" height="44"/>
<constraints>
<constraint firstAttribute="width" constant="44" id="Ke6-vY-hfR"/>
<constraint firstAttribute="height" constant="44" id="dAW-Ao-aCP"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Confirm with Side Button" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Kg6-VW-sWQ">
<rect key="frame" x="74" y="238.5" width="192" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="Kg6-VW-sWQ" firstAttribute="centerX" secondItem="T3T-T0-BjE" secondAttribute="centerX" id="1mu-uI-WBs"/>
<constraint firstItem="f6P-zA-4Z6" firstAttribute="leading" secondItem="iUb-N3-zJQ" secondAttribute="leading" id="4fO-Vb-c1b"/>
<constraint firstItem="oaH-fj-5IL" firstAttribute="top" secondItem="f6P-zA-4Z6" secondAttribute="bottom" id="5pf-rY-nN2"/>
<constraint firstItem="VyH-tv-SSg" firstAttribute="top" secondItem="yAp-G7-ISi" secondAttribute="bottom" constant="14" id="8XY-LN-bWU"/>
<constraint firstAttribute="trailing" secondItem="gm0-EC-Lnz" secondAttribute="trailing" id="9AL-vZ-n2U"/>
<constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="yAp-G7-ISi" secondAttribute="trailing" id="AXA-qv-kkz"/>
<constraint firstItem="87E-8y-Hmq" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" constant="11" id="BIU-fB-tRK"/>
<constraint firstItem="RXj-2n-vDf" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" constant="55" id="BzP-1P-eLN"/>
<constraint firstItem="yAp-G7-ISi" firstAttribute="top" secondItem="Kxr-1J-Ugh" secondAttribute="bottom" constant="75" id="EyY-qW-r0w"/>
<constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="Kxr-1J-Ugh" secondAttribute="trailing" id="Eyp-kE-nzO"/>
<constraint firstItem="Kxr-1J-Ugh" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="JTL-nt-Eik"/>
<constraint firstItem="DN7-AT-k3m" firstAttribute="centerY" secondItem="87E-8y-Hmq" secondAttribute="centerY" id="LiF-o2-czQ"/>
<constraint firstItem="VyH-tv-SSg" firstAttribute="trailing" secondItem="RXj-2n-vDf" secondAttribute="trailing" id="XHL-p4-hMl"/>
<constraint firstItem="87E-8y-Hmq" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="16" id="cbe-D7-ySr"/>
<constraint firstItem="T3T-T0-BjE" firstAttribute="top" secondItem="gm0-EC-Lnz" secondAttribute="bottom" constant="20" id="gOe-4k-Psx"/>
<constraint firstItem="T3T-T0-BjE" firstAttribute="centerX" secondItem="iN0-l3-epB" secondAttribute="centerX" id="gsk-we-k6U"/>
<constraint firstItem="f6P-zA-4Z6" firstAttribute="top" secondItem="iUb-N3-zJQ" secondAttribute="bottom" id="gzv-x0-4O2"/>
<constraint firstItem="JCZ-Gk-LId" firstAttribute="leading" secondItem="oaH-fj-5IL" secondAttribute="leading" id="iB1-6h-Q9f"/>
<constraint firstItem="Kg6-VW-sWQ" firstAttribute="top" secondItem="T3T-T0-BjE" secondAttribute="bottom" constant="8" id="j93-sE-NGH"/>
<constraint firstItem="gm0-EC-Lnz" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="16" id="jW2-Kn-Iq5"/>
<constraint firstItem="oaH-fj-5IL" firstAttribute="leading" secondItem="f6P-zA-4Z6" secondAttribute="leading" id="jkK-KZ-eo4"/>
<constraint firstItem="RXj-2n-vDf" firstAttribute="top" secondItem="Kxr-1J-Ugh" secondAttribute="bottom" constant="18" id="lbR-Bw-3fd"/>
<constraint firstItem="JCZ-Gk-LId" firstAttribute="centerY" secondItem="VyH-tv-SSg" secondAttribute="centerY" id="lnM-Vy-ktN"/>
<constraint firstItem="gm0-EC-Lnz" firstAttribute="top" secondItem="yAp-G7-ISi" secondAttribute="bottom" constant="45" id="mp2-UH-eyk"/>
<constraint firstAttribute="trailing" secondItem="DN7-AT-k3m" secondAttribute="trailing" constant="16" id="tw5-dM-7Z4"/>
<constraint firstItem="yAp-G7-ISi" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" constant="16" id="uHW-W7-BEd"/>
<constraint firstItem="iUb-N3-zJQ" firstAttribute="top" secondItem="Kxr-1J-Ugh" secondAttribute="bottom" constant="13" id="vtD-3q-L3b"/>
<constraint firstItem="iUb-N3-zJQ" firstAttribute="leading" secondItem="RXj-2n-vDf" secondAttribute="trailing" constant="16" id="y4w-Ig-EE4"/>
<constraint firstItem="Kxr-1J-Ugh" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" constant="45" id="zHC-4Z-Gu7"/>
</constraints>
<nil key="simulatedTopBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
<connections>
<outlet property="descLabel" destination="f6P-zA-4Z6" id="Uko-Rh-Hx9"/>
<outlet property="iconImageView" destination="RXj-2n-vDf" id="kYd-UV-4wW"/>
<outlet property="nameLabel" destination="iUb-N3-zJQ" id="kzc-aj-SmS"/>
</connections>
<point key="canvasLocation" x="12.800000000000001" y="31.934032983508249"/>
</view>
</objects>
<resources>
<image name="demo_icon" width="490" height="490"/>
</resources>
</document>
================================================
FILE: AppStoreDemo/Game/View/Download/DownloadClickView.swift
================================================
//
// DownloadClickView.swift
// AppStoreDemo
//
// Created by Allen long on 2019/9/5.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
class DownloadClickView: UIView,NibLoadable {
var timer: Timer?
override func awakeFromNib() {
super.awakeFromNib()
}
func startMoving() {
timer = Timer(timeInterval: 1.5, repeats: true, block: { _ in
self.animations()
})
timer?.fire()
RunLoop.main.add(timer!, forMode: .default)
}
func endMoving() {
timer?.invalidate()
timer = nil
}
private func animations() {
UIView.animateKeyframes(withDuration: 1, delay: 0, options: [], animations: {
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.25, animations: {
self.frame.origin.x -= GlobalConstants.clickBarWidth
})
UIView.addKeyframe(withRelativeStartTime: 0.25, relativeDuration: 0.5, animations: {
self.frame.origin.x += GlobalConstants.clickBarWidth
})
UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.75, animations: {
self.frame.origin.x -= GlobalConstants.clickBarWidth
})
UIView.addKeyframe(withRelativeStartTime: 0.75, relativeDuration: 1.0, animations: {
self.frame.origin.x += GlobalConstants.clickBarWidth
})
}, completion: nil)
}
}
================================================
FILE: AppStoreDemo/Game/View/Download/DownloadClickView.xib
================================================
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="DownloadClickView" customModule="AppStoreDemo" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="140" height="115"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Fb4-yR-I1B">
<rect key="frame" x="128" y="7.5" width="12" height="100"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="100" id="13A-aO-9xA"/>
<constraint firstAttribute="width" constant="12" id="bEK-Vj-e9T"/>
</constraints>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
<real key="value" value="3"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Double Click to install" textAlignment="right" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="KaE-LV-hOw">
<rect key="frame" x="10" y="31" width="113" height="53.5"/>
<constraints>
<constraint firstAttribute="width" constant="113" id="ABf-HV-B4c"/>
</constraints>
<fontDescription key="fontDescription" name="PingFangSC-Regular" family="PingFang SC" pointSize="19"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="Fb4-yR-I1B" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="centerY" id="fD9-Mk-kIt"/>
<constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="Fb4-yR-I1B" secondAttribute="trailing" id="fct-cv-ij0"/>
<constraint firstItem="Fb4-yR-I1B" firstAttribute="leading" secondItem="KaE-LV-hOw" secondAttribute="trailing" constant="5" id="hFq-4s-9bA"/>
<constraint firstItem="KaE-LV-hOw" firstAttribute="centerY" secondItem="Fb4-yR-I1B" secondAttribute="centerY" id="hLR-4n-6z6"/>
</constraints>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
<point key="canvasLocation" x="14.4" y="-127.28635682158921"/>
</view>
</objects>
</document>
================================================
FILE: AppStoreDemo/Game/View/Link/GameLinkTableView.swift
================================================
//
// GameLinkTableView.swift
// AppStoreDemo
//
// Created by Allen long on 2019/8/7.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
class GameLinkTableView: UITableView {
override init(frame: CGRect, style: UITableView.Style) {
super.init(frame: frame, style: style)
setupUI()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupUI() {
rowHeight = GlobalConstants.linkCellHeight
register(UITableViewCell.self, forCellReuseIdentifier: UITableViewCellID)
dataSource = self
separatorInset = UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 20)
}
}
extension GameLinkTableView: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return linkDataSource.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = dequeueReusableCell(withIdentifier: UITableViewCellID, for: indexPath)
cell.textLabel?.font = UIFont.systemFont(ofSize: 22)
cell.textLabel?.text = linkDataSource[indexPath.row]
cell.textLabel?.textColor = GlobalConstants.textBlueColor
return cell
}
}
fileprivate let UITableViewCellID = "UITableViewCellID"
fileprivate let linkDataSource: [String] = [
"Add a Payment Method",
"Parents' Guide to the App",
"About In-App Purchases",
"About Apps & Games for Your Kids",
"About Personalisation",
"New to the App Store",
]
================================================
FILE: AppStoreDemo/Game/View/Link/GameLinkTableViewCell.swift
================================================
//
// GameLinkTableViewCell.swift
// AppStoreDemo
//
// Created by Allen long on 2019/8/7.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
class GameLinkTableViewCell: UITableViewCell {
private lazy var headerView: CommonSectionHeaderView = {
let frame = CGRect(x: 0, y: 0, width: kScreenW, height: 42)
let it = CommonSectionHeaderView(frame: frame)
it.changeSectionTitle(with: "Quick Links")
return it
}()
private lazy var tableView: GameLinkTableView = {
let frame = CGRect(x: 0, y: 42, width: kScreenW, height: GlobalConstants.linkCellHeight * 6)
let it = GameLinkTableView(frame: frame)
return it
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupUI()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupUI() {
contentView.addSubview(headerView)
contentView.addSubview(tableView)
}
}
================================================
FILE: AppStoreDemo/Game/View/Recommand/GameRecommandCollectionView.swift
================================================
//
// GameRecommandCollectionView.swift
// AppStoreDemo
//
// Created by Allen long on 2019/8/6.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
class GameRecommandCollectionView: UICollectionView {
override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
super.init(frame: frame, collectionViewLayout: layout)
config()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func config() {
backgroundColor = .white
decelerationRate = UIScrollView.DecelerationRate.fast
ut_registerNibCell(RecommandCollectionViewCell.self)
showsHorizontalScrollIndicator = false
}
}
================================================
FILE: AppStoreDemo/Game/View/Recommand/GameRecommandTableViewCell.swift
================================================
//
// GameRecommandTableViewCell.swift
// AppStoreDemo
//
// Created by Allen long on 2019/8/6.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
class GameRecommandTableViewCell: UITableViewCell {
var detailClosure: (()->())?
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupUI()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupUI() {
contentView.addSubview(recommandCollectionView)
}
private lazy var recommandCollectionView: GameRecommandCollectionView = {
let itemSize = CGSize(width: kScreenW - 2 * GlobalConstants.leftMargin, height: GlobalConstants.recommandHeight)
let frame = CGRect(x: 0, y: 0, width: kScreenW, height: GlobalConstants.recommandHeight)
let layout = CommonCollectionFlowLayout(itemSize: itemSize)
let collectionView = GameRecommandCollectionView(frame: frame, collectionViewLayout: layout)
collectionView.dataSource = self
collectionView.delegate = self
return collectionView
}()
}
extension GameRecommandTableViewCell: UICollectionViewDataSource,UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == recommandCollectionView {
return RecommandDataSource.count
}
return 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == recommandCollectionView {
let cell = collectionView.ut_dequeueReusable(RecommandCollectionViewCell.self, for: indexPath)
cell.model = RecommandDataSource[indexPath.row]
return cell
}
return UICollectionViewCell()
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
detailClosure?()
}
}
fileprivate let RecommandDataSource: [GameRecommandModel] = [
GameRecommandModel(feature: "MAJOR UPDATE", name: "Onmyoji", desc: "Cards", coverImageName: "cover_1"),
GameRecommandModel(feature: "NEW GAME", name: "Clash Royale", desc: "Strategy", coverImageName: "cover_2"),
GameRecommandModel(feature: "REDISCOVER THIS", name: "Fantasy Westward Journey", desc: "Adventure", coverImageName: "cover_3")
]
================================================
FILE: AppStoreDemo/Game/View/Recommand/RecommandCollectionViewCell.swift
================================================
//
// RecommandCollectionViewCell.swift
// AppStoreDemo
//
// Created by Allen long on 2019/8/6.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
class RecommandCollectionViewCell: UICollectionViewCell {
@IBOutlet weak var featureLabel: UILabel!
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var descLabel: UILabel!
@IBOutlet weak var coverImageView: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
var model: GameRecommandModel! {
didSet {
featureLabel.text = model.feature
nameLabel.text = model.name
descLabel.text = model.desc
coverImageView.image = UIImage(named: model.coverImageName)
}
}
}
================================================
FILE: AppStoreDemo/Game/View/Recommand/RecommandCollectionViewCell.xib
================================================
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" id="gTV-IL-0wX" customClass="RecommandCollectionViewCell" customModule="AppStoreTodayDemo" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="269" height="312"/>
<autoresizingMask key="autoresizingMask"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="269" height="312"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ksh-3O-JUB">
<rect key="frame" x="0.0" y="12" width="264" height="14"/>
<constraints>
<constraint firstAttribute="height" constant="14" id="4XY-mK-22K"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="11"/>
<color key="textColor" red="0.039215686274509803" green="0.37254901960784315" blue="0.99607843137254903" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="FOr-7j-iyZ">
<rect key="frame" x="0.0" y="31" width="264" height="27"/>
<constraints>
<constraint firstAttribute="height" constant="27" id="n6e-19-2uq"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="22"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="4pJ-qq-aqw" userLabel="lineView">
<rect key="frame" x="0.0" y="1" width="269" height="1"/>
<color key="backgroundColor" red="0.8784313725490196" green="0.8784313725490196" blue="0.8784313725490196" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="height" constant="0.80000000000000004" id="fj9-Ef-W9Y"/>
</constraints>
</view>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Ihz-tS-UsA">
<rect key="frame" x="0.0" y="101" width="269" height="179"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
<real key="value" value="5"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="qhw-hX-BZR">
<rect key="frame" x="0.0" y="63" width="264" height="24"/>
<constraints>
<constraint firstAttribute="height" constant="24" id="rKO-B0-0eC"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="20"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</view>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="FOr-7j-iyZ" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" id="1Y4-vd-dz4"/>
<constraint firstItem="4pJ-qq-aqw" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" id="3Fa-af-gJH"/>
<constraint firstAttribute="bottom" secondItem="Ihz-tS-UsA" secondAttribute="bottom" constant="32" id="Bxp-Tm-a5r"/>
<constraint firstAttribute="trailing" secondItem="FOr-7j-iyZ" secondAttribute="trailing" constant="5" id="Gc0-fT-9Ru"/>
<constraint firstItem="Ihz-tS-UsA" firstAttribute="top" secondItem="qhw-hX-BZR" secondAttribute="bottom" constant="14" id="JWg-A9-dRk"/>
<constraint firstItem="Ksh-3O-JUB" firstAttribute="top" secondItem="4pJ-qq-aqw" secondAttribute="bottom" constant="10" id="O6P-vZ-Ocb"/>
<constraint firstAttribute="trailing" secondItem="Ihz-tS-UsA" secondAttribute="trailing" id="YHp-Bp-4ca"/>
<constraint firstItem="FOr-7j-iyZ" firstAttribute="top" secondItem="Ksh-3O-JUB" secondAttribute="bottom" constant="5" id="eSP-eV-t3d"/>
<constraint firstAttribute="trailing" secondItem="qhw-hX-BZR" secondAttribute="trailing" constant="5" id="ih9-ZX-L1O"/>
<constraint firstItem="Ksh-3O-JUB" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" id="oGY-mn-e6K"/>
<constraint firstItem="qhw-hX-BZR" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" id="onC-st-p5f"/>
<constraint firstItem="4pJ-qq-aqw" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" constant="1" id="rhi-Gx-9h1"/>
<constraint firstAttribute="trailing" secondItem="Ksh-3O-JUB" secondAttribute="trailing" constant="5" id="skl-Hg-3BK"/>
<constraint firstItem="qhw-hX-BZR" firstAttribute="top" secondItem="FOr-7j-iyZ" secondAttribute="bottom" constant="5" id="smI-Wd-jyA"/>
<constraint firstAttribute="trailing" secondItem="4pJ-qq-aqw" secondAttribute="trailing" id="tdh-Mf-2QG"/>
<constraint firstItem="Ihz-tS-UsA" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" id="yIh-WX-jLS"/>
</constraints>
<viewLayoutGuide key="safeArea" id="ZTg-uK-7eu"/>
<size key="customSize" width="269" height="312"/>
<connections>
<outlet property="coverImageView" destination="Ihz-tS-UsA" id="eBd-Va-pFq"/>
<outlet property="descLabel" destination="qhw-hX-BZR" id="xJb-nK-dtz"/>
<outlet property="featureLabel" destination="Ksh-3O-JUB" id="8oH-Te-0jx"/>
<outlet property="nameLabel" destination="FOr-7j-iyZ" id="VAX-qu-7T4"/>
</connections>
<point key="canvasLocation" x="100.72463768115942" y="-205.58035714285714"/>
</collectionViewCell>
</objects>
</document>
================================================
FILE: AppStoreDemo/Game/View/Topic/GameTopicCollectionView.swift
================================================
//
// GameTopicCollectionView.swift
// AppStoreDemo
//
// Created by Allen long on 2019/8/6.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
class GameTopicCollectionView: UICollectionView {
override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
super.init(frame: frame, collectionViewLayout: layout)
config()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func config() {
backgroundColor = .white
decelerationRate = UIScrollView.DecelerationRate.fast
ut_registerNibCell(GameTopicCollectionViewCell.self)
showsHorizontalScrollIndicator = false
}
}
================================================
FILE: AppStoreDemo/Game/View/Topic/GameTopicCollectionViewCell.swift
================================================
//
// GameTopicCollectionViewCell.swift
// AppStoreDemo
//
// Created by Allen long on 2019/8/6.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
protocol GameTopicCollectionViewCellDelegate: class {
func gameTopicCollectionViewCellDidClickGet(_ topicCell: GameTopicCollectionViewCell)
}
class GameTopicCollectionViewCell: UICollectionViewCell {
@IBOutlet weak var iconImageView: UIImageView!
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var descLabel: UILabel!
@IBOutlet weak var lineView: UIView!
weak var delegate: GameTopicCollectionViewCellDelegate?
var model: GameTopicModel! {
didSet {
iconImageView.image = UIImage(named: model.iconImageName)
nameLabel.text = model.name
descLabel.text = model.desc
}
}
@IBAction func getAction(_ sender: UIButton) {
delegate?.gameTopicCollectionViewCellDidClickGet(self)
}
}
================================================
FILE: AppStoreDemo/Game/View/Topic/GameTopicCollectionViewCell.xib
================================================
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" id="gTV-IL-0wX" customClass="GameTopicCollectionViewCell" customModule="AppStoreDemo" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="322" height="87"/>
<autoresizingMask key="autoresizingMask"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="322" height="87"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="EZb-bM-8Tl">
<rect key="frame" x="0.0" y="8" width="62" height="62"/>
<constraints>
<constraint firstAttribute="width" constant="62" id="Auj-Bl-al7"/>
<constraint firstAttribute="height" constant="62" id="fUm-d0-x2g"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="OZk-FT-FLd">
<rect key="frame" x="70" y="18" width="42" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Kua-jD-qdJ">
<rect key="frame" x="70" y="44" width="33" height="16"/>
<fontDescription key="fontDescription" type="system" pointSize="13"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="hXZ-EQ-7Aq">
<rect key="frame" x="249" y="28.5" width="73" height="30"/>
<color key="backgroundColor" red="0.94117647059999998" green="0.94117647059999998" blue="0.96862745100000003" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="width" constant="73" id="TeE-4c-m8T"/>
<constraint firstAttribute="height" constant="30" id="q7e-kw-wlV"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="15"/>
<state key="normal" title="Get"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
<real key="value" value="15"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
<connections>
<action selector="getAction:" destination="gTV-IL-0wX" eventType="touchUpInside" id="qki-Wa-ztp"/>
</connections>
</button>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="0hw-LK-ltQ">
<rect key="frame" x="70" y="86" width="252" height="1"/>
<color key="backgroundColor" red="0.8784313725490196" green="0.8784313725490196" blue="0.8784313725490196" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="height" constant="0.80000000000000004" id="fBJ-Wf-tCA"/>
</constraints>
</view>
</subviews>
</view>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="Kua-jD-qdJ" firstAttribute="leading" secondItem="EZb-bM-8Tl" secondAttribute="trailing" constant="8" id="1fP-XW-KK8"/>
<constraint firstItem="OZk-FT-FLd" firstAttribute="leading" secondItem="EZb-bM-8Tl" secondAttribute="trailing" constant="8" id="Aq5-3u-nud"/>
<constraint firstItem="0hw-LK-ltQ" firstAttribute="leading" secondItem="Kua-jD-qdJ" secondAttribute="leading" id="DXU-bD-tus"/>
<constraint firstItem="EZb-bM-8Tl" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" constant="8" id="Gfe-B6-xje"/>
<constraint firstItem="EZb-bM-8Tl" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" id="T3H-lW-2vV"/>
<constraint firstItem="Kua-jD-qdJ" firstAttribute="top" secondItem="OZk-FT-FLd" secondAttribute="bottom" constant="5" id="W9I-x6-Shc"/>
<constraint firstAttribute="bottom" secondItem="0hw-LK-ltQ" secondAttribute="bottom" id="aGQ-fl-JXo"/>
<constraint firstItem="hXZ-EQ-7Aq" firstAttribute="centerY" secondItem="gTV-IL-0wX" secondAttribute="centerY" id="dOk-bg-CQ1"/>
<constraint firstAttribute="trailing" secondItem="hXZ-EQ-7Aq" secondAttribute="trailing" id="f9Q-r1-Sk4"/>
<constraint firstItem="OZk-FT-FLd" firstAttribute="top" secondItem="EZb-bM-8Tl" secondAttribute="top" constant="10" id="mh0-MW-V4J"/>
<constraint firstItem="ZTg-uK-7eu" firstAttribute="trailing" secondItem="0hw-LK-ltQ" secondAttribute="trailing" id="w09-oG-70H"/>
</constraints>
<viewLayoutGuide key="safeArea" id="ZTg-uK-7eu"/>
<size key="customSize" width="322" height="87"/>
<connections>
<outlet property="descLabel" destination="Kua-jD-qdJ" id="7nY-rM-5mQ"/>
<outlet property="iconImageView" destination="EZb-bM-8Tl" id="juN-9O-5EN"/>
<outlet property="lineView" destination="0hw-LK-ltQ" id="SoG-rm-mez"/>
<outlet property="nameLabel" destination="OZk-FT-FLd" id="g87-eP-RwD"/>
</connections>
<point key="canvasLocation" x="131.8840579710145" y="62.611607142857139"/>
</collectionViewCell>
</objects>
</document>
================================================
FILE: AppStoreDemo/Game/View/Topic/GameTopicTableViewCell.swift
================================================
//
// GameTopicTableViewCell.swift
// AppStoreDemo
//
// Created by Allen long on 2019/8/6.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
class GameTopicTableViewCell: UITableViewCell {
var detailClosure: (()->())?
var downloadClosure: ((_ model: GameTopicModel)->())?
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupUI()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupUI() {
contentView.addSubview(headerView)
contentView.addSubview(topicCollectionView)
}
private lazy var headerView: CommonSectionHeaderView = {
let frame = CGRect(x: 0, y: 0, width: kScreenW, height: 42)
let it = CommonSectionHeaderView(frame: frame)
it.changeSectionTitle(with: "What We're Playing")
return it
}()
private lazy var topicCollectionView: GameTopicCollectionView = {
let itemSize = CGSize(width: kScreenW - 2 * GlobalConstants.leftMargin, height: 80)
let frame = CGRect(x: 0, y: 42, width: kScreenW, height: 80 * 3)
let layout = CommonCollectionFlowLayout(itemSize: itemSize)
let collectionView = GameTopicCollectionView(frame: frame, collectionViewLayout: layout)
collectionView.dataSource = self
collectionView.delegate = self
return collectionView
}()
}
extension GameTopicTableViewCell: UICollectionViewDataSource,UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == topicCollectionView {
return TopicDataSource.count
}
return 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == topicCollectionView {
let cell = collectionView.ut_dequeueReusable(GameTopicCollectionViewCell.self, for: indexPath)
cell.delegate = self
cell.model = TopicDataSource[indexPath.row]
cell.lineView.isHidden = (((indexPath.row + 1) % 3 == 0) || (indexPath.row == TopicDataSource.count - 1))
return cell
}
return UICollectionViewCell()
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
detailClosure?()
}
}
extension GameTopicTableViewCell: GameTopicCollectionViewCellDelegate {
func gameTopicCollectionViewCellDidClickGet(_ topicCell: GameTopicCollectionViewCell) {
guard let indexPath = topicCollectionView.indexPath(for: topicCell) else { return }
downloadClosure?(TopicDataSource[indexPath.item])
}
}
fileprivate let TopicDataSource: [GameTopicModel] = [
GameTopicModel(name: "Bullet Hell", desc: "Casual", iconImageName: "logo_broadcast"),
GameTopicModel(name: "Hot Wheels", desc: "Strategy", iconImageName: "logo_car"),
GameTopicModel(name: "SpellForce - Heroes", desc: "Card", iconImageName: "logo_jump"),
GameTopicModel(name: "Farm Punks", desc: "Role-Playing", iconImageName: "logo_smile"),
GameTopicModel(name: "Super Spinball", desc: "A musical journey awaits", iconImageName: "logo_weibo"),
]
================================================
FILE: AppStoreDemo/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>$(DEVELOPMENT_LANGUAGE)</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>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIUserInterfaceStyle</key>
<string>Light</string>
</dict>
</plist>
================================================
FILE: AppStoreDemo/Main.storyboard
================================================
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15400" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="7gp-xX-vDA">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15404"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Tab Bar Controller-->
<scene sceneID="YMh-JZ-4oj">
<objects>
<tabBarController automaticallyAdjustsScrollViewInsets="NO" id="7gp-xX-vDA" sceneMemberID="viewController">
<toolbarItems/>
<tabBar key="tabBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="VyS-0d-PkQ">
<rect key="frame" x="0.0" y="0.0" width="1000" height="1000"/>
<autoresizingMask key="autoresizingMask"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</tabBar>
<connections>
<segue destination="Aqn-rC-J8Q" kind="relationship" relationship="viewControllers" id="nto-yd-aVS"/>
<segue destination="0bk-jh-Gf1" kind="relationship" relationship="viewControllers" id="ZWJ-Ff-wnV"/>
<segue destination="sfx-ou-gVP" kind="relationship" relationship="viewControllers" id="FEh-q6-so7"/>
<segue destination="gLP-mw-QVg" kind="relationship" relationship="viewControllers" id="dm8-sU-NtG"/>
</connections>
</tabBarController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Zpc-zI-abD" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-458" y="-306"/>
</scene>
<!--Search-->
<scene sceneID="Owz-qb-slY">
<objects>
<tableViewController id="Qxn-VB-fUK" customClass="SearchTableViewController" customModule="AppStoreDemo" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="QEW-sE-ETH">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<view key="tableFooterView" contentMode="scaleToFill" id="4ai-DU-AEW">
<rect key="frame" x="0.0" y="0.0" width="414" height="44"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</view>
<connections>
<outlet property="dataSource" destination="Qxn-VB-fUK" id="r8T-64-Iwg"/>
<outlet property="delegate" destination="Qxn-VB-fUK" id="fwu-HP-vV6"/>
</connections>
</tableView>
<navigationItem key="navigationItem" title="Search" largeTitleDisplayMode="always" id="pP4-E8-Y0F"/>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Wp5-D3-Lwg" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2061" y="806"/>
</scene>
<!--Updates-->
<scene sceneID="5or-tl-5GI">
<objects>
<tableViewController id="S1q-f5-Z8X" customClass="UpdateTableViewController" customModule="AppStoreDemo" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" allowsSelection="NO" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="Zgl-og-TgX">
<rect key="frame" x="0.0" y="0.0" width="414" height="756"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<inset key="separatorInset" minX="20" minY="0.0" maxX="0.0" maxY="0.0"/>
<connections>
<outlet property="dataSource" destination="S1q-f5-Z8X" id="dmv-eC-fVg"/>
<outlet property="delegate" destination="S1q-f5-Z8X" id="zq0-ox-mKA"/>
</connections>
</tableView>
<navigationItem key="navigationItem" title="Updates" largeTitleDisplayMode="always" id="Q6X-mc-MFL"/>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="gmK-MI-F1S" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="880" y="1026"/>
</scene>
<!--Today-->
<scene sceneID="ja9-Bk-QuO">
<objects>
<tableViewController id="Aqn-rC-J8Q" customClass="TodayViewController" customModule="AppStoreDemo" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="zun-x5-pzu">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<connections>
<outlet property="dataSource" destination="Aqn-rC-J8Q" id="of2-9S-K8j"/>
<outlet property="delegate" destination="Aqn-rC-J8Q" id="Dmr-kZ-Fbf"/>
</connections>
</tableView>
<tabBarItem key="tabBarItem" title="Today" image="tabbar_today" id="wO6-Bm-6Qm"/>
<navigationItem key="navigationItem" id="DTm-bH-qfa"/>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="ReK-BJ-5vP" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1209" y="-1187"/>
</scene>
<!--Search-->
<scene sceneID="tOJ-8S-p6p">
<objects>
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="gLP-mw-QVg" sceneMemberID="viewController">
<tabBarItem key="tabBarItem" title="Search" image="tabbar_search" id="M1r-rh-aBa"/>
<toolbarItems/>
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" largeTitles="YES" id="lmM-4Y-70L">
<rect key="frame" x="0.0" y="44" width="414" height="96"/>
<autoresizingMask key="autoresizingMask"/>
<color key="barTintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</navigationBar>
<nil name="viewControllers"/>
<connections>
<segue destination="Qxn-VB-fUK" kind="relationship" relationship="rootViewController" id="KjB-XS-G6z"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="eGc-GV-yKt" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2061" y="66"/>
</scene>
<!--Updates-->
<scene sceneID="k4R-VK-LO4">
<objects>
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="sfx-ou-gVP" sceneMemberID="viewController">
<tabBarItem key="tabBarItem" title="Updates" image="tabbar_updates" id="ztJ-x8-NSN"/>
<toolbarItems/>
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" translucent="NO" largeTitles="YES" id="d1t-VT-7Y5">
<rect key="frame" x="0.0" y="44" width="414" height="96"/>
<autoresizingMask key="autoresizingMask"/>
<color key="barTintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</navigationBar>
<nil name="viewControllers"/>
<connections>
<segue destination="S1q-f5-Z8X" kind="relationship" relationship="rootViewController" id="r9c-06-fFn"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="hY8-Hj-V9m" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="881" y="291"/>
</scene>
<!--Games-->
<scene sceneID="cjX-zC-40O">
<objects>
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="0bk-jh-Gf1" sceneMemberID="viewController">
<tabBarItem key="tabBarItem" title="Games" image="tabbar_games" id="f89-e2-CjX"/>
<toolbarItems/>
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" translucent="NO" largeTitles="YES" id="txg-gB-TGy">
<rect key="frame" x="0.0" y="44" width="414" height="96"/>
<autoresizingMask key="autoresizingMask"/>
<color key="barTintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</navigationBar>
<nil name="viewControllers"/>
<connections>
<segue destination="wxJ-JV-VGz" kind="relationship" relationship="rootViewController" id="4ge-Hg-8WZ"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="efs-GP-7qb" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2060.8695652173915" y="-938.16964285714278"/>
</scene>
<!--Game-->
<scene sceneID="U3a-Wp-BNs">
<objects>
<tableViewController id="wxJ-JV-VGz" customClass="GameTableViewController" customModule="AppStoreDemo" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="KJw-Rc-EV2">
<rect key="frame" x="0.0" y="0.0" width="414" height="756"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<connections>
<outlet property="dataSource" destination="wxJ-JV-VGz" id="hIa-3P-DDK"/>
<outlet property="delegate" destination="wxJ-JV-VGz" id="PaO-Wf-Xdj"/>
</connections>
</tableView>
<navigationItem key="navigationItem" title="Game" largeTitleDisplayMode="always" id="d9w-dm-4CR"/>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="aNN-aQ-LD5" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2929" y="-938"/>
</scene>
</scenes>
<resources>
<image name="tabbar_games" width="20" height="22"/>
<image name="tabbar_search" width="22" height="22"/>
<image name="tabbar_today" width="18" height="22"/>
<image name="tabbar_updates" width="18" height="22"/>
</resources>
</document>
================================================
FILE: AppStoreDemo/Search/Controller/SearchTableViewController.swift
================================================
//
// SearchTableViewController.swift
// AppStoreDemo
//
// Created by Allen long on 2019/8/2.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
class SearchTableViewController: UITableViewController {
private var searchController: UISearchController!
override func viewDidLoad() {
super.viewDidLoad()
setNavigationBarBottomLineHidden(true)
setupSearchController()
tableView.ut_registerClassCell(SearchTableViewCell.self)
}
private func setupSearchController() {
searchController = UISearchController(searchResultsController: nil)
searchController.searchBar.autocapitalizationType = .none
searchController.searchBar.placeholder = "App Store"
searchController.isActive = true
definesPresentationContext = true
if #available(iOS 11.0, *) {
// For iOS 11 and later, place the search bar in the navigation bar.
navigationItem.searchController = searchController
// Make the search bar always visible.
navigationItem.hidesSearchBarWhenScrolling = false
} else {
// For iOS 10 and earlier, place the search controller's search bar in the table view's header.
tableView.tableHeaderView = searchController.searchBar
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataList.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.ut_dequeueReusable(SearchTableViewCell.self, for: indexPath)
cell.textLabel?.text = dataList[indexPath.row]
cell.canChangeHightlighted = (indexPath.row != 0)
return cell
}
}
fileprivate let dataList: [String] = [
"Hot Search",
"Daily life",
"League of Legends",
"Wechat",
"Game of Thrones",
"Hupu JRS",
"Game Center",
"QQ Music"
]
================================================
FILE: AppStoreDemo/Search/View/SearchTableViewCell.swift
================================================
//
// SearchTableViewCell.swift
// AppStoreDemo
//
// Created by Allen long on 2019/8/2.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
class SearchTableViewCell: UITableViewCell {
var canChangeHightlighted: Bool = false {
didSet {
if !canChangeHightlighted {
textLabel?.textColor = .black
}
}
}
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupUI()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func setHighlighted(_ highlighted: Bool, animated: Bool) {
super.setHighlighted(highlighted, animated: animated)
if !canChangeHightlighted { return }
if highlighted {
textLabel?.textColor = .white
backgroundColor = GlobalConstants.textBlueColor
} else {
textLabel?.textColor = GlobalConstants.textBlueColor
backgroundColor = .white
}
}
private func setupUI() {
textLabel?.textColor = GlobalConstants.textBlueColor
textLabel?.font = UIFont.systemFont(ofSize: 19)
selectionStyle = .none
}
}
================================================
FILE: AppStoreDemo/Today/Controller/CardDetailViewController.swift
================================================
//
// CardDetailViewController.swift
// AppStoreDemo
//
// Created by Allen long on 2019/7/31.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
class CardDetailViewController: UIViewController {
override var prefersStatusBarHidden: Bool {
return true
}
var dismissClosure: (()->())?
//the point when start to interactive
var interactiveStartingPoint: CGPoint? = nil
var draggingDownToDismiss = false
let cell: TodayTableViewCell!
private lazy var dismissPanGesture: UIPanGestureRecognizer = {
let ges = UIPanGestureRecognizer()
ges.maximumNumberOfTouches = 1
ges.addTarget(self, action: #selector(handleDismissPan(gesture:)))
ges.delegate = self
return ges
}()
lazy var scrollView: DetailScrollView = {
let frame = self.view.bounds
let view = DetailScrollView(frame: frame)
view.delegate = self
return view
}()
lazy var closeBtn: UIButton = {
let btn = UIButton()
btn.frame = CGRect(x: kScreenW - 20 - 30, y: 20, width: 30, height: 30)
btn.setImage(#imageLiteral(resourceName: "close_button"), for: .normal)
btn.addTarget(self, action: #selector(closeAction), for: .touchUpInside)
return btn
}()
init(cell: TodayTableViewCell) {
self.cell = cell
super.init(nibName: nil, bundle: nil)
self.setupTranstion()
}
private func setupTranstion() {
modalPresentationStyle = .custom
transitioningDelegate = self
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
getImageFromCell()
}
private func setupUI() {
self.view.backgroundColor = .white
self.view.layer.masksToBounds = true
view.addSubview(scrollView)
view.addSubview(closeBtn)
view.addGestureRecognizer(dismissPanGesture)
if #available(iOS 11.0, *) {
scrollView.contentInsetAdjustmentBehavior = .never
} else {
automaticallyAdjustsScrollViewInsets = false
}
}
private func getImageFromCell() {
scrollView.imageView.image = cell.bgImageView.image
}
@objc private func closeAction() {
dismiss(animated: true, completion: nil)
dismissClosure?()
}
@objc private func handleDismissPan(gesture: UIPanGestureRecognizer) {
if !draggingDownToDismiss {
return
}
let startingPoint: CGPoint
if let p = interactiveStartingPoint {
startingPoint = p
} else {
startingPoint = gesture.location(in: nil)
interactiveStartingPoint = startingPoint
}
let currentLocation = gesture.location(in: nil)
var progress = (currentLocation.y - startingPoint.y) / 100
//prevent viewController bigger when scrolling up
if currentLocation.y <= startingPoint.y {
progress = 0
}
if progress >= 1.0 {
dismiss(animated: true, completion: nil)
dismissClosure?()
stopDismissPanGesture(gesture)
return
}
let targetShrinkScale: CGFloat = 0.86
let currentScale: CGFloat = 1 - (1 - targetShrinkScale) * progress
switch gesture.state {
case .began,.changed:
scrollView.isScrollEnabled = false
gesture.view?.transform = CGAffineTransform(scaleX: currentScale, y: currentScale)
gesture.view?.layer.cornerRadius = GlobalConstants.toDayCardCornerRadius * (progress)
scrollView.showsVerticalScrollIndicator = false
case .cancelled,.ended:
scrollView.isScrollEnabled = true
stopDismissPanGesture(gesture)
default:
break
}
}
//当下拉Offset超过100或取消下拉手势时,执行此方法
private func stopDismissPanGesture(_ gesture: UIPanGestureRecognizer) {
draggingDownToDismiss = false
interactiveStartingPoint = nil
scrollView.showsVerticalScrollIndicator = true
UIView.animate(withDuration: 0.2) {
gesture.view?.transform = CGAffineTransform.identity
}
}
}
extension CardDetailViewController: UIViewControllerTransitioningDelegate {
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return TodayAnimationTransition(animationType: .present)
}
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return TodayAnimationTransition(animationType: .dismiss)
}
func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
return CardPresentationController(presentedViewController: presented, presenting: presenting)
}
}
extension CardDetailViewController: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView.contentOffset.y < 0 {
scrollView.contentOffset = .zero
draggingDownToDismiss = true
}
}
}
extension CardDetailViewController: UIGestureRecognizerDelegate {
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
}
================================================
FILE: AppStoreDemo/Today/Controller/CardPresentationController.swift
================================================
//
// TodayPresentationController.swift
// AppStoreDemo
//
// Created by Allen long on 2019/8/2.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
class CardPresentationController: UIPresentationController {
private lazy var blurView = UIVisualEffectView(effect: nil)
override var shouldRemovePresentersView: Bool {
return false
}
override func presentationTransitionWillBegin() {
let container = containerView!
blurView.translatesAutoresizingMaskIntoConstraints = false
container.addSubview(blurView)
blurView.edges(to: container)
blurView.alpha = 0.0
presentingViewController.beginAppearanceTransition(false, animated: false)
presentedViewController.transitionCoordinator!.animate(alongsideTransition: { (ctx) in
self.blurView.effect = UIBlurEffect(style: .light)
self.blurView.alpha = 1
}) { (ctx) in }
}
override func presentationTransitionDidEnd(_ completed: Bool) {
presentingViewController.endAppearanceTransition()
}
override func dismissalTransitionWillBegin() {
presentingViewController.beginAppearanceTransition(true, animated: true)
presentedViewController.transitionCoordinator!.animate(alongsideTransition: { (ctx) in
self.blurView.alpha = 0.0
}, completion: nil)
}
override func dismissalTransitionDidEnd(_ completed: Bool) {
presentingViewController.endAppearanceTransition()
if completed {
blurView.removeFromSuperview()
}
}
}
================================================
FILE: AppStoreDemo/Today/Controller/TodayViewController.swift
================================================
//
// TodayViewController.swift
// AppStoreDemo
//
// Created by Allen long on 2019/7/31.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
class TodayViewController: UITableViewController {
var selectedCell: TodayTableViewCell?
var statusBarShouldBeHidden = false
//we need to set `View controller-based status bar appearance = YES` in info.plist.
//so we can be able to hide statusBar.
override var prefersStatusBarHidden: Bool {
return statusBarShouldBeHidden
}
override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation {
return .slide
}
lazy var headerView: TodayTableHeaderView = {
let frame = CGRect(x: 0, y: 0, width: kScreenW, height: 96)
let view = TodayTableHeaderView(frame: frame)
view.iconButtonClosure = { [weak self] in
guard let StrongSelf = self else { return }
StrongSelf.presentUserTableViewController()
}
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
setupTableView()
}
private func setupTableView() {
tableView.ut_registerClassCell(TodayTableViewCell.self)
tableView.separatorStyle = .none
tableView.rowHeight = GlobalConstants.toDayCardRowH
tableView.tableHeaderView = headerView
}
private func updateStatusBarAndTabbarFrame(visible: Bool) {
statusBarShouldBeHidden = !visible
UIView.animate(withDuration: 0.25) {
self.setNeedsStatusBarAppearanceUpdate()
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.ut_dequeueReusable(TodayTableViewCell.self, for: indexPath)
cell.selectionStyle = .none
if indexPath.row == 0 {
cell.bgImageView.image = #imageLiteral(resourceName: "cover_4")
} else {
cell.bgImageView.image = #imageLiteral(resourceName: "cover_5")
}
return cell
}
override func tableView(_ tableView: UITableView, didHighlightRowAt indexPath: IndexPath) {
guard let row = tableView.cellForRow(at: indexPath) as? TodayTableViewCell else { return }
UIView.animate(withDuration: 0.1) {
row.bgBackView.transform = CGAffineTransform(scaleX: 0.95, y: 0.95)
}
}
override func tableView(_ tableView: UITableView, didUnhighlightRowAt indexPath: IndexPath) {
guard let row = tableView.cellForRow(at: indexPath) as? TodayTableViewCell else { return }
UIView.animate(withDuration: 0.3) {
row.bgBackView.transform = CGAffineTransform(scaleX: 1.0, y: 1.0)
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let cell = tableView.cellForRow(at: indexPath) as? TodayTableViewCell else { return }
selectedCell = cell
let detailVC = CardDetailViewController(cell: cell)
detailVC.dismissClosure = { [weak self] in
guard let StrongSelf = self else { return }
StrongSelf.updateStatusBarAndTabbarFrame(visible: true)
}
updateStatusBarAndTabbarFrame(visible: false)
present(detailVC, animated: true, completion: nil)
}
}
================================================
FILE: AppStoreDemo/Today/Model/TodayAnimationTransition.swift
================================================
//
// TodayAnimationTransition.swift
// AppStoreDemo
//
// Created by Allen long on 2019/7/31.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
fileprivate let transitonDuration: TimeInterval = 1.0
enum AnimationType {
case present
case dismiss
}
class TodayAnimationTransition: NSObject {
let animationType: AnimationType!
init(animationType: AnimationType) {
self.animationType = animationType
super.init()
}
}
extension TodayAnimationTransition: UIViewControllerAnimatedTransitioning {
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return transitonDuration
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
if animationType == .present {
animationForPresent(using: transitionContext)
} else {
animationForDismiss(using: transitionContext)
}
}
func animationForPresent(using transitionContext: UIViewControllerContextTransitioning) {
let containerView = transitionContext.containerView
//1.Get fromVC and toVC
guard let fromVC = transitionContext.viewController(forKey: .from) as? UITabBarController else { return }
guard let tableViewController = fromVC.viewControllers?.first as? TodayViewController else { return }
guard let toVC = transitionContext.viewController(forKey: .to) as? CardDetailViewController else { return }
guard let selectedCell = tableViewController.selectedCell else { return }
let frame = selectedCell.convert(selectedCell.bgBackView.frame, to: fromVC.view)
//2.Set presentation original size.
toVC.view.frame = frame
toVC.scrollView.imageView.frame.size.width = GlobalConstants.todayCardSize.width
toVC.scrollView.imageView.frame.size.height = GlobalConstants.todayCardSize.height
containerView.addSubview(toVC.view)
//3.Change original size to final size with animation.
UIView.animate(withDuration: transitonDuration, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0, options: [], animations: {
toVC.view.frame = UIScreen.main.bounds
toVC.scrollView.imageView.frame.size.width = kScreenW
toVC.scrollView.imageView.frame.size.height = GlobalConstants.cardDetailTopImageH
toVC.closeBtn.alpha = 1
fromVC.tabBar.frame.origin.y = kScreenH
}) { (completed) in
transitionContext.completeTransition(completed)
}
}
func animationForDismiss(using transitionContext: UIViewControllerContextTransitioning) {
guard let fromVC = transitionContext.viewController(forKey: .from) as? CardDetailViewController else { return }
guard let toVC = transitionContext.viewController(forKey: .to) as? UITabBarController else { return }
guard let tableViewController = toVC.viewControllers?.first as? TodayViewController else { return }
guard let selectedCell = tableViewController.selectedCell else { return }
UIView.animate(withDuration: transitonDuration - 0.3, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0, options: [], animations: {
let frame = selectedCell.convert(selectedCell.bgBackView.frame, to: toVC.view)
fromVC.view.frame = frame
fromVC.view.layer.cornerRadius = GlobalConstants.toDayCardCornerRadius
fromVC.scrollView.imageView.frame.size.width = GlobalConstants.todayCardSize.width
fromVC.scrollView.imageView.frame.size.height = GlobalConstants.todayCardSize.height
fromVC.closeBtn.alpha = 0
toVC.tabBar.frame.origin.y = kScreenH - toVC.tabBar.frame.height
}) { (completed) in
transitionContext.completeTransition(completed)
toVC.view.addSubview(toVC.tabBar)
}
}
}
================================================
FILE: AppStoreDemo/Today/View/DetailScrollView.swift
================================================
//
// DetailScrollView.swift
// AppStoreDemo
//
// Created by Allen long on 2019/7/31.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
class DetailScrollView: UIScrollView {
let bgBackView = UIView()
let imageView = UIImageView()
let textView = UITextView()
override init(frame: CGRect) {
super.init(frame: frame)
setupUI()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupUI() {
bgBackView.frame = CGRect(x: 0, y: 0, width: kScreenW, height: GlobalConstants.cardDetailTopImageH)
bgBackView.layer.masksToBounds = true
imageView.frame = bgBackView.bounds
imageView.isUserInteractionEnabled = true
imageView.contentMode = .scaleAspectFill
let textViewWidth = kScreenW - 2 * textViewLeftMargin
let font = UIFont.boldSystemFont(ofSize: 15)
let textHeight = textViewText.calculateHeightWith(width: textViewWidth, font: font)
textView.frame = CGRect(x: textViewLeftMargin, y: bgBackView.frame.height + textViewTopMargin, width: textViewWidth, height: textHeight + textViewBottomMargin)
textView.text = textViewText
textView.font = font
textView.textColor = .gray
bgBackView.addSubview(imageView)
addSubview(bgBackView)
addSubview(textView)
contentSize = CGSize(width: kScreenW, height: bgBackView.frame.height + textViewTopMargin + textView.frame.height + textViewBottomMargin)
}
}
fileprivate let textViewLeftMargin: CGFloat = 20
fileprivate let textViewTopMargin: CGFloat = 40
fileprivate let textViewBottomMargin: CGFloat = 50
fileprivate let textViewText = "Thank you. I'm honored to be with you today for your commencement from one of the finest universities in the world. Truth be told, i never graduated from college and this is the closest I've ever gotten to a college gradution. \n\nToday i want to tell you three stories from my life. That's it. No big deal. Just three stories. The first story is about connecting the dots. \n\ndropped out of Reed College after the first 6 months, but then stayed around as a drop-in for another 18 months or so before I really quit. So why did I drop out? \n\nIt started before I was born. My biological mother was a young,unwed college graduate student, and she decided to put me up for adoption. She felt very strongly that I should be adopted by college graduates, so everything was all set for me to be adopted at birth by a lawyer and his wife. Except that when I popped out they decided at the last minute that they really wanted a girl. So my parents, who were on a waiting list, got a call in the middle of the night asking: 'We got an unexpected baby boy; do you want him?' They said: 'Of course.' My biological mother found out later that my mother had never graduated from college and my father had never graduated from high school. She refused to sign the final adoption papers. She only relented a few months later when my parents promised that I would go to college."
================================================
FILE: AppStoreDemo/Today/View/TodayTableHeaderView.swift
================================================
//
// TodayTableHeaderView.swift
// AppStoreDemo
//
// Created by Allen long on 2019/7/31.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
class TodayTableHeaderView: UIView {
let dateLabel = UILabel()
let todayLabel = UILabel()
let iconButton = UIButton()
var iconButtonClosure: (()->())?
override init(frame: CGRect) {
super.init(frame: frame)
setupUI()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupUI() {
dateLabel.text = "TUESDAY, JULY 10"
dateLabel.textColor = .gray
dateLabel.font = UIFont.boldSystemFont(ofSize: 13)
dateLabel.frame = CGRect(x: 20, y: 33, width: 200, height: 15)
todayLabel.text = "Today"
todayLabel.font = UIFont.boldSystemFont(ofSize: 34)
todayLabel.frame = CGRect(x: 20, y: 48, width: 200, height: 40)
iconButton.setImage(#imageLiteral(resourceName: "demo_icon"), for: .normal)
iconButton.setImage(#imageLiteral(resourceName: "demo_icon"), for: .highlighted)
iconButton.frame = CGRect(x: kScreenW - 20 - 40, y: 46, width: 35, height: 35)
iconButton.layer.cornerRadius = GlobalConstants.iconCornerRadius
iconButton.layer.borderColor = GlobalConstants.iconBorderColor
iconButton.layer.borderWidth = GlobalConstants.iconBorderWidth
iconButton.addTarget(self, action: #selector(iconButtonAction), for: .touchUpInside)
addSubview(dateLabel)
addSubview(todayLabel)
addSubview(iconButton)
}
@objc private func iconButtonAction() {
iconButtonClosure?()
}
}
================================================
FILE: AppStoreDemo/Today/View/TodayTableViewCell.swift
================================================
//
// TodayTableViewCell.swift
// AppStoreDemo
//
// Created by Allen long on 2019/7/31.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
class TodayTableViewCell: UITableViewCell {
let bgBackView = UIView()
let bgImageView = UIImageView()
let emptyView = UIView()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupUI()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupUI() {
bgBackView.addSubview(bgImageView)
contentView.addSubview(bgBackView)
contentView.addSubview(emptyView)
bgBackView.frame = CGRect(x: GlobalConstants.leftMargin, y: 0, width: GlobalConstants.todayCardSize.width, height: GlobalConstants.todayCardSize.height)
bgBackView.layer.shadowColor = UIColor.black.cgColor
bgBackView.layer.shadowOpacity = 0.4
bgBackView.layer.shadowOffset = CGSize(width: 0, height: 1)
bgImageView.frame = bgBackView.bounds
bgImageView.contentMode = .scaleAspectFill
bgImageView.layer.cornerRadius = GlobalConstants.toDayCardCornerRadius
bgImageView.layer.masksToBounds = true
emptyView.backgroundColor = UIColor.white.withAlphaComponent(0)
emptyView.frame = CGRect(x: 0, y: bgImageView.frame.size.height, width: GlobalConstants.todayCardSize.width, height: GlobalConstants.toDayCardRowH - GlobalConstants.todayCardSize.height)
}
}
================================================
FILE: AppStoreDemo/Update/Controller/UpdateTableViewController.swift
================================================
//
// UpdateTableViewController.swift
// AppStoreDemo
//
// Created by Erwin on 2019/8/4.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
class UpdateTableViewController: UITableViewController {
var dataSource = DataSource
//record cellHeight to prevent flickering when tapped `more`
var cellHeights: [IndexPath: CGFloat] = [:]
override func viewDidLoad() {
super.viewDidLoad()
adjustNavigationForiOS13()
setNavigationBarBottomLineHidden(true)
addIconButtonOnNavigationBar()
configTableView()
}
private func configTableView() {
tableView.ut_registerNibCell(UpdateTableViewCell.self)
}
//add iconButton to LargeTitleView
@objc func rightButtonTapped(_ btn: UIButton) {
presentUserTableViewController()
}
// MARK: - Table view data source
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return dataSource.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.ut_dequeueReusable(UpdateTableViewCell.self, for: indexPath)
cell.isFirstCell = (indexPath.row == 0)
cell.updateClosure = { [weak self] tappedCell in
guard let StrongSelf = self else { return }
StrongSelf.dataSource[indexPath.row].showMore = true
StrongSelf.tableView.reloadRows(at: [indexPath], with: .none)
print(indexPath)
}
cell.model = dataSource[indexPath.row]
return cell
}
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cellHeights[indexPath] = cell.frame.size.height
}
override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
if let height = cellHeights[indexPath] {
return height
} else {
return UITableView.automaticDimension
}
}
override func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView.contentOffset.y > 0 {
setNavigationBarBottomLineHidden(false)
} else {
setNavigationBarBottomLineHidden(true)
}
}
}
fileprivate let DataSource: [UpdateModel] = [
UpdateModel(appName: "Huajiao Live", updateDate: "Today", iconImageStr: "logo_broadcast", updateContent: "[Play] Music radio broadcasting page revision, more immersed in music exploration \n\n[Mine] Rewriting sets the position of the night mode \n\n[Radio] Let's go with DJ and get up!", version: "2.0.0", size: 35.7, showMore: false),
UpdateModel(appName: "Sina Weibo", updateDate: "Today", iconImageStr: "logo_weibo", updateContent: "-Performance improvements and bug fixed", version: "5.3.3", size: 32.5, showMore: false),
UpdateModel(appName: "Sougou-input", updateDate: "Yesterday", iconImageStr: "logo_smile", updateContent: "Fix bug and to be better for you", version: "2.1.1", size: 42.2, showMore: false),
UpdateModel(appName: "Guazi Car", updateDate: "Yesterday", iconImageStr: "logo_car", updateContent: "Sometimes, a polish is all you need. No big chages, just a shine", version: "1.5.0", size: 28.0, showMore: false),
UpdateModel(appName: "Fly-chat", updateDate: "2019/08/02", iconImageStr: "logo_jump", updateContent: "This update includes bug fixed and user interface improvements", version: "1.5.6", size: 33.0, showMore: false),
]
================================================
FILE: AppStoreDemo/Update/Model/UpdateModel.swift
================================================
//
// UpdateModel.swift
// AppStoreDemo
//
// Created by Allen long on 2019/8/5.
// Copyright © 2019 Utimes. All rights reserved.
//
import Foundation
struct UpdateModel {
let appName: String
let updateDate: String
let iconImageStr: String
let updateContent: String
let version: String
let size: Float
var showMore: Bool
}
================================================
FILE: AppStoreDemo/Update/View/UpdateTableViewCell.swift
================================================
//
// UpdateTableViewCell.swift
// AppStoreDemo
//
// Created by Allen long on 2019/8/5.
// Copyright © 2019 Utimes. All rights reserved.
//
import UIKit
class UpdateTableViewCell: UITableViewCell {
// MARK: - IBOutlets
@IBOutlet weak var topLeftLabel: UILabel!
@IBOutlet weak var updateAllBtn: UIButton!
@IBOutlet weak var contentLabel: UILabel!
@IBOutlet weak var showMoreBtn: UIButton!
@IBOutlet weak var iconImageView: UIImageView!
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var dateLabel: UILabel!
@IBOutlet weak var versionAndSizeLabel: UILabel!
// MARK: - Constraint
@IBOutlet weak var iconImageViewTopMargin: NSLayoutConstraint!
@IBOutlet weak var contentLabelBottomMargin: NSLayoutConstraint!
// MARK: - Properties
// if the cell is the first cell in tableView, it would show more content than other cells
var isFirstCell: Bool = false {
didSet {
iconImageViewTopMargin.constant = isFirstCell ? 48 : 16
topLeftLabel.isHidden = !isFirstCell
updateAllBtn.isHidden = !isFirstCell
}
}
var model: UpdateModel! {
didSet {
iconImageView.image = UIImage(named: model.iconImageStr)
nameLabel.text = model.appName
dateLabel.text = model.updateDate
contentLabel.text = model.updateContent
versionAndSizeLabel.text = "Version " + model.version + " · " + String(model.size) + " MB"
showMoreBtn.isHidden = model.showMore
contentLabel.numberOfLines = model.showMore ? 0 : 1
contentLabelBottomMargin.constant = model.showMore ? 60 : 20
versionAndSizeLabel.isHidden = !model.showMore
}
}
var updateClosure: ((UpdateTableViewCell)->())?
// MARK: - IBAction
@IBAction func updateAllBtnAction(_ sender: UIButton) {
}
@IBAction func showMoreBtnAction(_ sender: UIButton) {
updateClosure?(self)
}
override func awakeFromNib() {
super.awakeFromNib()
}
}
================================================
FILE: AppStoreDemo/Update/View/UpdateTableViewCell.xib
================================================
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" rowHeight="171" id="KGk-i7-Jjw" customClass="UpdateTableViewCell" customModule="AppStoreDemo" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="460" height="168"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
<rect key="frame" x="0.0" y="0.0" width="460" height="167.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="CBp-XE-tH2" userLabel="topLine">
<rect key="frame" x="20" y="1" width="420" height="0.5"/>
<color key="backgroundColor" red="0.8784313725490196" green="0.8784313725490196" blue="0.8784313725490196" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="height" constant="0.5" id="if4-Fh-NQt"/>
</constraints>
</view>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="logo_weibo" translatesAutoresizingMaskIntoConstraints="NO" id="TqU-LX-Ops">
<rect key="frame" x="20" y="17.5" width="62" height="62"/>
<constraints>
<constraint firstAttribute="width" constant="62" id="LbP-RU-7nB"/>
<constraint firstAttribute="height" constant="62" id="tbN-0b-D21"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="CKm-YC-TFA">
<rect key="frame" x="94" y="30.5" width="262" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hrX-rc-0n3">
<rect key="frame" x="94" y="54.5" width="33" height="16"/>
<fontDescription key="fontDescription" type="system" pointSize="13"/>
<color key="textColor" red="0.56862745098039214" green="0.56862745098039214" blue="0.58039215686274503" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="bKo-X1-PHr">
<rect key="frame" x="366" y="33.5" width="74" height="30"/>
<color key="backgroundColor" red="0.94117647058823528" green="0.94117647058823528" blue="0.96862745098039216" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="width" constant="74" id="GWP-J9-IBB"/>
<constraint firstAttribute="height" constant="30" id="GhT-m1-HQB"/>
</constraints>
<fontDescription key="fontDescription" name="Helvetica-Bold" family="Helvetica" pointSize="14"/>
<state key="normal" title="UPDATE"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
<real key="value" value="15"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</button>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="ContentLabel" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jbI-7A-QXF" userLabel="contentLabel">
<rect key="frame" x="20" y="102.5" width="382" height="32"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Pending" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="URh-dw-PlV">
<rect key="frame" x="20" y="14.5" width="77.5" height="24"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="20"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="wV8-ap-qcL">
<rect key="frame" x="356" y="9.5" width="84" height="34"/>
<fontDescription key="fontDescription" type="system" pointSize="18"/>
<state key="normal" title="Update All"/>
<connections>
<action selector="updateAllBtnAction:" destination="KGk-i7-Jjw" eventType="touchUpInside" id="syz-AN-flT"/>
</connections>
</button>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="psI-hH-YSr">
<rect key="frame" x="20" y="128.5" width="40" height="20"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" red="0.55686274509803924" green="0.55686274509803924" blue="0.5725490196078431" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="uHz-PH-qrY">
<rect key="frame" x="404" y="103.5" width="36" height="30"/>
<constraints>
<constraint firstAttribute="width" constant="36" id="VvL-68-2C4"/>
<constraint firstAttribute="height" constant="30" id="t1j-5p-qYx"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<state key="normal" title="more"/>
<connections>
<action selector="showMoreBtnAction:" destination="KGk-i7-Jjw" eventType="touchUpInside" id="sMp-zR-WoG"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="uHz-PH-qrY" firstAttribute="leading" secondItem="jbI-7A-QXF" secondAttribute="trailing" constant="2" id="1PO-qm-MMz"/>
<constraint firstAttribute="trailing" secondItem="wV8-ap-qcL" secondAttribute="trailing" constant="20" id="1rT-bS-hqn"/>
<constraint firstItem="wV8-ap-qcL" firstAttribute="centerY" secondItem="URh-dw-PlV" secondAttribute="centerY" id="2ZZ-n3-jcW"/>
<constraint firstItem="URh-dw-PlV" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="20" id="7Ro-Su-ilD"/>
<constraint firstItem="CKm-YC-TFA" firstAttribute="leading" secondItem="TqU-LX-Ops" secondAttribute="trailing" constant="12" id="AF2-ao-2by"/>
<constraint firstAttribute="bottom" secondItem="psI-hH-YSr" secondAttribute="bottom" constant="19" id="AKu-nb-rza"/>
<constraint firstItem="CKm-YC-TFA" firstAttribute="top" secondItem="TqU-LX-Ops" secondAttribute="top" constant="13" id="BnW-bk-nGq"/>
<constraint firstItem="jbI-7A-QXF" firstAttribute="top" secondItem="TqU-LX-Ops" secondAttribute="bottom" constant="23" id="EV6-Ii-AM5"/>
<constraint firstItem="CBp-XE-tH2" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="20" id="HQJ-md-mYn"/>
<constraint firstItem="jbI-7A-QXF" firstAttribute="leading" secondItem="TqU-LX-Ops" secondAttribute="leading" id="L8C-DI-Jrc"/>
<constraint firstAttribute="trailing" secondItem="bKo-X1-PHr" secondAttribute="trailing" constant="20" id="XdE-at-J52"/>
<constraint firstItem="uHz-PH-qrY" firstAttribute="centerY" secondItem="jbI-7A-QXF" secondAttribute="centerY" id="XhY-Rf-LzJ"/>
<constraint firstItem="psI-hH-
gitextract_vi5lwdol/ ├── AppStoreDemo/ │ ├── AppDelegate.swift │ ├── Assets.xcassets/ │ │ ├── AppIcon.appiconset/ │ │ │ └── Contents.json │ │ ├── Contents.json │ │ ├── DS_Store │ │ ├── app_logo/ │ │ │ ├── Contents.json │ │ │ ├── logo_broadcast.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── logo_car.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── logo_game.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── logo_jump.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── logo_smile.imageset/ │ │ │ │ └── Contents.json │ │ │ └── logo_weibo.imageset/ │ │ │ └── Contents.json │ │ ├── common/ │ │ │ ├── Contents.json │ │ │ ├── circle_download.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── close_button.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── demo_icon.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── detail_download.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── detail_more.imageset/ │ │ │ │ └── Contents.json │ │ │ └── navigation_back.imageset/ │ │ │ └── Contents.json │ │ ├── cover/ │ │ │ ├── Contents.json │ │ │ ├── cover_1.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── cover_2.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── cover_3.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── cover_4.imageset/ │ │ │ │ └── Contents.json │ │ │ └── cover_5.imageset/ │ │ │ └── Contents.json │ │ ├── cover_detail/ │ │ │ ├── Contents.json │ │ │ ├── cover_detail.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── cover_detail1.imageset/ │ │ │ │ └── Contents.json │ │ │ └── cover_detail2.imageset/ │ │ │ └── Contents.json │ │ └── tabBar/ │ │ ├── Contents.json │ │ ├── tabbar_apps.imageset/ │ │ │ └── Contents.json │ │ ├── tabbar_games.imageset/ │ │ │ └── Contents.json │ │ ├── tabbar_search.imageset/ │ │ │ └── Contents.json │ │ ├── tabbar_today.imageset/ │ │ │ └── Contents.json │ │ └── tabbar_updates.imageset/ │ │ └── Contents.json │ ├── Base.lproj/ │ │ └── LaunchScreen.storyboard │ ├── Common/ │ │ ├── CommonCollectionFlowLayout.swift │ │ └── CommonSectionHeaderView.swift │ ├── Extension/ │ │ ├── String+Extension.swift │ │ ├── UIColor+Extension.swift │ │ ├── UITableView+Extension.swift │ │ ├── UIView+Extension.swift │ │ └── UIViewController+Extension.swift │ ├── Game/ │ │ ├── Controller/ │ │ │ ├── DetailViewController.swift │ │ │ ├── DownloadPresentationController.swift │ │ │ ├── DownloadViewController.swift │ │ │ └── GameTableViewController.swift │ │ ├── Model/ │ │ │ ├── DownloadTransitioning.swift │ │ │ ├── GameRecommandModel.swift │ │ │ └── GameTopicModel.swift │ │ └── View/ │ │ ├── Detail/ │ │ │ ├── DetailInfomationTableViewCell.swift │ │ │ ├── DetailInformationCell.swift │ │ │ ├── DetailNavigationView.swift │ │ │ ├── DetailNewFeaturesCell.swift │ │ │ ├── DetailNewFeaturesCell.xib │ │ │ ├── DetailPreviewCell.swift │ │ │ ├── DetailPreviewCollectionView.swift │ │ │ ├── DetailPreviewCollectionViewCell.swift │ │ │ ├── DetailTopInfoCell.swift │ │ │ └── DetailTopInfoCell.xib │ │ ├── Download/ │ │ │ ├── DownloadBottomView.swift │ │ │ ├── DownloadBottomView.xib │ │ │ ├── DownloadClickView.swift │ │ │ └── DownloadClickView.xib │ │ ├── Link/ │ │ │ ├── GameLinkTableView.swift │ │ │ └── GameLinkTableViewCell.swift │ │ ├── Recommand/ │ │ │ ├── GameRecommandCollectionView.swift │ │ │ ├── GameRecommandTableViewCell.swift │ │ │ ├── RecommandCollectionViewCell.swift │ │ │ └── RecommandCollectionViewCell.xib │ │ └── Topic/ │ │ ├── GameTopicCollectionView.swift │ │ ├── GameTopicCollectionViewCell.swift │ │ ├── GameTopicCollectionViewCell.xib │ │ └── GameTopicTableViewCell.swift │ ├── Info.plist │ ├── Main.storyboard │ ├── Search/ │ │ ├── Controller/ │ │ │ └── SearchTableViewController.swift │ │ └── View/ │ │ └── SearchTableViewCell.swift │ ├── Today/ │ │ ├── Controller/ │ │ │ ├── CardDetailViewController.swift │ │ │ ├── CardPresentationController.swift │ │ │ └── TodayViewController.swift │ │ ├── Model/ │ │ │ ├── DS_Store │ │ │ └── TodayAnimationTransition.swift │ │ └── View/ │ │ ├── DetailScrollView.swift │ │ ├── TodayTableHeaderView.swift │ │ └── TodayTableViewCell.swift │ ├── Update/ │ │ ├── Controller/ │ │ │ └── UpdateTableViewController.swift │ │ ├── Model/ │ │ │ └── UpdateModel.swift │ │ └── View/ │ │ ├── UpdateTableViewCell.swift │ │ └── UpdateTableViewCell.xib │ ├── User/ │ │ ├── Controller/ │ │ │ └── UserTableViewController.swift │ │ └── View/ │ │ └── User.storyboard │ └── Utils/ │ ├── GlobalConstants.swift │ ├── GlobalFunctions.swift │ └── StarView.swift ├── AppStoreDemo.xcodeproj/ │ ├── project.pbxproj │ ├── project.xcworkspace/ │ │ ├── contents.xcworkspacedata │ │ ├── xcshareddata/ │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcuserdata/ │ │ └── fengbufang.xcuserdatad/ │ │ └── UserInterfaceState.xcuserstate │ └── xcuserdata/ │ └── fengbufang.xcuserdatad/ │ ├── xcdebugger/ │ │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes/ │ └── xcschememanagement.plist ├── README.md └── 中文简介.md
Condensed preview — 102 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (294K chars).
[
{
"path": "AppStoreDemo/AppDelegate.swift",
"chars": 475,
"preview": "//\n// AppDelegate.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/7/31.\n// Copyright © 2019 Utimes. All ri"
},
{
"path": "AppStoreDemo/Assets.xcassets/AppIcon.appiconset/Contents.json",
"chars": 1668,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"iphone\",\n \"size\" : \"20x20\",\n \"scale\" : \"2x\"\n },\n {\n \"idiom\""
},
{
"path": "AppStoreDemo/Assets.xcassets/Contents.json",
"chars": 62,
"preview": "{\n \"info\" : {\n \"version\" : 1,\n \"author\" : \"xcode\"\n }\n}"
},
{
"path": "AppStoreDemo/Assets.xcassets/app_logo/Contents.json",
"chars": 62,
"preview": "{\n \"info\" : {\n \"version\" : 1,\n \"author\" : \"xcode\"\n }\n}"
},
{
"path": "AppStoreDemo/Assets.xcassets/app_logo/logo_broadcast.imageset/Contents.json",
"chars": 312,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"logo_broadcast.jpeg\",\n \"scale\" : \"1x\"\n }"
},
{
"path": "AppStoreDemo/Assets.xcassets/app_logo/logo_car.imageset/Contents.json",
"chars": 305,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"logo_car.jpg\",\n \"scale\" : \"1x\"\n },\n {"
},
{
"path": "AppStoreDemo/Assets.xcassets/app_logo/logo_game.imageset/Contents.json",
"chars": 306,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"logo_game.jpg\",\n \"scale\" : \"1x\"\n },\n "
},
{
"path": "AppStoreDemo/Assets.xcassets/app_logo/logo_jump.imageset/Contents.json",
"chars": 306,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"logo_jump.jpg\",\n \"scale\" : \"1x\"\n },\n "
},
{
"path": "AppStoreDemo/Assets.xcassets/app_logo/logo_smile.imageset/Contents.json",
"chars": 307,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"logo_smile.jpg\",\n \"scale\" : \"1x\"\n },\n "
},
{
"path": "AppStoreDemo/Assets.xcassets/app_logo/logo_weibo.imageset/Contents.json",
"chars": 308,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"logo_weibo.jpeg\",\n \"scale\" : \"1x\"\n },\n "
},
{
"path": "AppStoreDemo/Assets.xcassets/common/Contents.json",
"chars": 62,
"preview": "{\n \"info\" : {\n \"version\" : 1,\n \"author\" : \"xcode\"\n }\n}"
},
{
"path": "AppStoreDemo/Assets.xcassets/common/circle_download.imageset/Contents.json",
"chars": 360,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : \"universal\",\n "
},
{
"path": "AppStoreDemo/Assets.xcassets/common/close_button.imageset/Contents.json",
"chars": 354,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : \"universal\",\n "
},
{
"path": "AppStoreDemo/Assets.xcassets/common/demo_icon.imageset/Contents.json",
"chars": 306,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"demo_icon.png\",\n \"scale\" : \"1x\"\n },\n "
},
{
"path": "AppStoreDemo/Assets.xcassets/common/detail_download.imageset/Contents.json",
"chars": 360,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : \"universal\",\n "
},
{
"path": "AppStoreDemo/Assets.xcassets/common/detail_more.imageset/Contents.json",
"chars": 352,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : \"universal\",\n "
},
{
"path": "AppStoreDemo/Assets.xcassets/common/navigation_back.imageset/Contents.json",
"chars": 312,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : \"universal\",\n "
},
{
"path": "AppStoreDemo/Assets.xcassets/cover/Contents.json",
"chars": 62,
"preview": "{\n \"info\" : {\n \"version\" : 1,\n \"author\" : \"xcode\"\n }\n}"
},
{
"path": "AppStoreDemo/Assets.xcassets/cover/cover_1.imageset/Contents.json",
"chars": 305,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"cover_1.jpeg\",\n \"scale\" : \"1x\"\n },\n {"
},
{
"path": "AppStoreDemo/Assets.xcassets/cover/cover_2.imageset/Contents.json",
"chars": 305,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"cover_2.jpeg\",\n \"scale\" : \"1x\"\n },\n {"
},
{
"path": "AppStoreDemo/Assets.xcassets/cover/cover_3.imageset/Contents.json",
"chars": 305,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"cover_3.jpeg\",\n \"scale\" : \"1x\"\n },\n {"
},
{
"path": "AppStoreDemo/Assets.xcassets/cover/cover_4.imageset/Contents.json",
"chars": 305,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"cover_4.jpeg\",\n \"scale\" : \"1x\"\n },\n {"
},
{
"path": "AppStoreDemo/Assets.xcassets/cover/cover_5.imageset/Contents.json",
"chars": 305,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"cover_5.jpeg\",\n \"scale\" : \"1x\"\n },\n {"
},
{
"path": "AppStoreDemo/Assets.xcassets/cover_detail/Contents.json",
"chars": 62,
"preview": "{\n \"info\" : {\n \"version\" : 1,\n \"author\" : \"xcode\"\n }\n}"
},
{
"path": "AppStoreDemo/Assets.xcassets/cover_detail/cover_detail.imageset/Contents.json",
"chars": 309,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"cover_detail.jpg\",\n \"scale\" : \"1x\"\n },\n "
},
{
"path": "AppStoreDemo/Assets.xcassets/cover_detail/cover_detail1.imageset/Contents.json",
"chars": 310,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"cover_detail1.jpg\",\n \"scale\" : \"1x\"\n },\n"
},
{
"path": "AppStoreDemo/Assets.xcassets/cover_detail/cover_detail2.imageset/Contents.json",
"chars": 310,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"cover_detail2.jpg\",\n \"scale\" : \"1x\"\n },\n"
},
{
"path": "AppStoreDemo/Assets.xcassets/tabBar/Contents.json",
"chars": 62,
"preview": "{\n \"info\" : {\n \"version\" : 1,\n \"author\" : \"xcode\"\n }\n}"
},
{
"path": "AppStoreDemo/Assets.xcassets/tabBar/tabbar_apps.imageset/Contents.json",
"chars": 352,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : \"universal\",\n "
},
{
"path": "AppStoreDemo/Assets.xcassets/tabBar/tabbar_games.imageset/Contents.json",
"chars": 354,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : \"universal\",\n "
},
{
"path": "AppStoreDemo/Assets.xcassets/tabBar/tabbar_search.imageset/Contents.json",
"chars": 356,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : \"universal\",\n "
},
{
"path": "AppStoreDemo/Assets.xcassets/tabBar/tabbar_today.imageset/Contents.json",
"chars": 354,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : \"universal\",\n "
},
{
"path": "AppStoreDemo/Assets.xcassets/tabBar/tabbar_updates.imageset/Contents.json",
"chars": 358,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : \"universal\",\n "
},
{
"path": "AppStoreDemo/Base.lproj/LaunchScreen.storyboard",
"chars": 1658,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard"
},
{
"path": "AppStoreDemo/Common/CommonCollectionFlowLayout.swift",
"chars": 1836,
"preview": "//\n// GameCollectionFlowLayout.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/8/6.\n// Copyright © 2019 Ut"
},
{
"path": "AppStoreDemo/Common/CommonSectionHeaderView.swift",
"chars": 1461,
"preview": "//\n// CommonSectionHeaderView.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/8/9.\n// Copyright © 2019 Uti"
},
{
"path": "AppStoreDemo/Extension/String+Extension.swift",
"chars": 625,
"preview": "//\n// String+Extension.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/8/2.\n// Copyright © 2019 Utimes. Al"
},
{
"path": "AppStoreDemo/Extension/UIColor+Extension.swift",
"chars": 344,
"preview": "//\n// UIColor+Extension.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/8/5.\n// Copyright © 2019 Utimes. A"
},
{
"path": "AppStoreDemo/Extension/UITableView+Extension.swift",
"chars": 2509,
"preview": "//\n// UITableView+Extension.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/8/5.\n// Copyright © 2019 Utime"
},
{
"path": "AppStoreDemo/Extension/UIView+Extension.swift",
"chars": 1640,
"preview": "//\n// UIView+Extension.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/8/2.\n// Copyright © 2019 Utimes. Al"
},
{
"path": "AppStoreDemo/Extension/UIViewController+Extension.swift",
"chars": 4593,
"preview": "//\n// UIViewController+Extension.swift\n// AppStoreDemo\n//\n// Created by Erwin on 2019/8/4.\n// Copyright © 2019 Utime"
},
{
"path": "AppStoreDemo/Game/Controller/DetailViewController.swift",
"chars": 6093,
"preview": "//\n// DetailViewController.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/8/7.\n// Copyright © 2019 Utimes"
},
{
"path": "AppStoreDemo/Game/Controller/DownloadPresentationController.swift",
"chars": 1821,
"preview": "//\n// DownloadPresentationController.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/9/5.\n// Copyright © 2"
},
{
"path": "AppStoreDemo/Game/Controller/DownloadViewController.swift",
"chars": 3039,
"preview": "//\n// DownloadViewController.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/9/5.\n// Copyright © 2019 Utim"
},
{
"path": "AppStoreDemo/Game/Controller/GameTableViewController.swift",
"chars": 2992,
"preview": "//\n// GameTableViewController.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/8/6.\n// Copyright © 2019 Uti"
},
{
"path": "AppStoreDemo/Game/Model/DownloadTransitioning.swift",
"chars": 3469,
"preview": "//\n// DownloadTransitioning.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/9/5.\n// Copyright © 2019 Utime"
},
{
"path": "AppStoreDemo/Game/Model/GameRecommandModel.swift",
"chars": 291,
"preview": "//\n// GameRecommandModel.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/8/6.\n// Copyright © 2019 Utimes. "
},
{
"path": "AppStoreDemo/Game/Model/GameTopicModel.swift",
"chars": 262,
"preview": "//\n// GameTopicModel.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/8/6.\n// Copyright © 2019 Utimes. All "
},
{
"path": "AppStoreDemo/Game/View/Detail/DetailInfomationTableViewCell.swift",
"chars": 1913,
"preview": "//\n// DetailInfomationTableViewCell.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/8/9.\n// Copyright © 20"
},
{
"path": "AppStoreDemo/Game/View/Detail/DetailInformationCell.swift",
"chars": 2237,
"preview": "//\n// DetailInformationCell.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/8/9.\n// Copyright © 2019 Utime"
},
{
"path": "AppStoreDemo/Game/View/Detail/DetailNavigationView.swift",
"chars": 1155,
"preview": "//\n// DetailNavigationView.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/8/7.\n// Copyright © 2019 Utimes"
},
{
"path": "AppStoreDemo/Game/View/Detail/DetailNewFeaturesCell.swift",
"chars": 501,
"preview": "//\n// DetailNewFeaturesCell.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/8/8.\n// Copyright © 2019 Utime"
},
{
"path": "AppStoreDemo/Game/View/Detail/DetailNewFeaturesCell.xib",
"chars": 7833,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVe"
},
{
"path": "AppStoreDemo/Game/View/Detail/DetailPreviewCell.swift",
"chars": 2306,
"preview": "//\n// DetailPreviewCell.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/8/8.\n// Copyright © 2019 Utimes. A"
},
{
"path": "AppStoreDemo/Game/View/Detail/DetailPreviewCollectionView.swift",
"chars": 774,
"preview": "//\n// DetailPreviewCollectionView.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/8/8.\n// Copyright © 2019"
},
{
"path": "AppStoreDemo/Game/View/Detail/DetailPreviewCollectionViewCell.swift",
"chars": 750,
"preview": "//\n// DetailPreviewCollectionViewCell.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/8/8.\n// Copyright © "
},
{
"path": "AppStoreDemo/Game/View/Detail/DetailTopInfoCell.swift",
"chars": 561,
"preview": "//\n// DetailTopInfoCell.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/8/8.\n// Copyright © 2019 Utimes. A"
},
{
"path": "AppStoreDemo/Game/View/Detail/DetailTopInfoCell.xib",
"chars": 15266,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVe"
},
{
"path": "AppStoreDemo/Game/View/Download/DownloadBottomView.swift",
"chars": 884,
"preview": "//\n// DownloadBottomView.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/9/5.\n// Copyright © 2019 Utimes. "
},
{
"path": "AppStoreDemo/Game/View/Download/DownloadBottomView.xib",
"chars": 15708,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVe"
},
{
"path": "AppStoreDemo/Game/View/Download/DownloadClickView.swift",
"chars": 1497,
"preview": "//\n// DownloadClickView.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/9/5.\n// Copyright © 2019 Utimes. A"
},
{
"path": "AppStoreDemo/Game/View/Download/DownloadClickView.xib",
"chars": 4186,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVe"
},
{
"path": "AppStoreDemo/Game/View/Link/GameLinkTableView.swift",
"chars": 1621,
"preview": "//\n// GameLinkTableView.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/8/7.\n// Copyright © 2019 Utimes. A"
},
{
"path": "AppStoreDemo/Game/View/Link/GameLinkTableViewCell.swift",
"chars": 1131,
"preview": "//\n// GameLinkTableViewCell.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/8/7.\n// Copyright © 2019 Utime"
},
{
"path": "AppStoreDemo/Game/View/Recommand/GameRecommandCollectionView.swift",
"chars": 772,
"preview": "//\n// GameRecommandCollectionView.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/8/6.\n// Copyright © 2019"
},
{
"path": "AppStoreDemo/Game/View/Recommand/GameRecommandTableViewCell.swift",
"chars": 2547,
"preview": "//\n// GameRecommandTableViewCell.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/8/6.\n// Copyright © 2019 "
},
{
"path": "AppStoreDemo/Game/View/Recommand/RecommandCollectionViewCell.swift",
"chars": 793,
"preview": "//\n// RecommandCollectionViewCell.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/8/6.\n// Copyright © 2019"
},
{
"path": "AppStoreDemo/Game/View/Recommand/RecommandCollectionViewCell.xib",
"chars": 8782,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVe"
},
{
"path": "AppStoreDemo/Game/View/Topic/GameTopicCollectionView.swift",
"chars": 769,
"preview": "//\n// GameTopicCollectionView.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/8/6.\n// Copyright © 2019 Uti"
},
{
"path": "AppStoreDemo/Game/View/Topic/GameTopicCollectionViewCell.swift",
"chars": 970,
"preview": "//\n// GameTopicCollectionViewCell.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/8/6.\n// Copyright © 2019"
},
{
"path": "AppStoreDemo/Game/View/Topic/GameTopicCollectionViewCell.xib",
"chars": 8207,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVe"
},
{
"path": "AppStoreDemo/Game/View/Topic/GameTopicTableViewCell.swift",
"chars": 3406,
"preview": "//\n// GameTopicTableViewCell.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/8/6.\n// Copyright © 2019 Utim"
},
{
"path": "AppStoreDemo/Info.plist",
"chars": 1520,
"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": "AppStoreDemo/Main.storyboard",
"chars": 13691,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3"
},
{
"path": "AppStoreDemo/Search/Controller/SearchTableViewController.swift",
"chars": 2076,
"preview": "//\n// SearchTableViewController.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/8/2.\n// Copyright © 2019 U"
},
{
"path": "AppStoreDemo/Search/View/SearchTableViewCell.swift",
"chars": 1352,
"preview": "//\n// SearchTableViewCell.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/8/2.\n// Copyright © 2019 Utimes."
},
{
"path": "AppStoreDemo/Today/Controller/CardDetailViewController.swift",
"chars": 5764,
"preview": "//\n// CardDetailViewController.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/7/31.\n// Copyright © 2019 U"
},
{
"path": "AppStoreDemo/Today/Controller/CardPresentationController.swift",
"chars": 1625,
"preview": "//\n// TodayPresentationController.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/8/2.\n// Copyright © 2019"
},
{
"path": "AppStoreDemo/Today/Controller/TodayViewController.swift",
"chars": 3532,
"preview": "//\n// TodayViewController.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/7/31.\n// Copyright © 2019 Utimes"
},
{
"path": "AppStoreDemo/Today/Model/TodayAnimationTransition.swift",
"chars": 4025,
"preview": "//\n// TodayAnimationTransition.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/7/31.\n// Copyright © 2019 U"
},
{
"path": "AppStoreDemo/Today/View/DetailScrollView.swift",
"chars": 3170,
"preview": "//\n// DetailScrollView.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/7/31.\n// Copyright © 2019 Utimes. A"
},
{
"path": "AppStoreDemo/Today/View/TodayTableHeaderView.swift",
"chars": 1739,
"preview": "//\n// TodayTableHeaderView.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/7/31.\n// Copyright © 2019 Utime"
},
{
"path": "AppStoreDemo/Today/View/TodayTableViewCell.swift",
"chars": 1633,
"preview": "//\n// TodayTableViewCell.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/7/31.\n// Copyright © 2019 Utimes."
},
{
"path": "AppStoreDemo/Update/Controller/UpdateTableViewController.swift",
"chars": 3651,
"preview": "//\n// UpdateTableViewController.swift\n// AppStoreDemo\n//\n// Created by Erwin on 2019/8/4.\n// Copyright © 2019 Utimes"
},
{
"path": "AppStoreDemo/Update/Model/UpdateModel.swift",
"chars": 357,
"preview": "//\n// UpdateModel.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/8/5.\n// Copyright © 2019 Utimes. All rig"
},
{
"path": "AppStoreDemo/Update/View/UpdateTableViewCell.swift",
"chars": 2131,
"preview": "//\n// UpdateTableViewCell.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/8/5.\n// Copyright © 2019 Utimes."
},
{
"path": "AppStoreDemo/Update/View/UpdateTableViewCell.xib",
"chars": 14682,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVe"
},
{
"path": "AppStoreDemo/User/Controller/UserTableViewController.swift",
"chars": 904,
"preview": "//\n// UserTableViewController.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/8/5.\n// Copyright © 2019 Uti"
},
{
"path": "AppStoreDemo/User/View/User.storyboard",
"chars": 25831,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3"
},
{
"path": "AppStoreDemo/Utils/GlobalConstants.swift",
"chars": 1794,
"preview": "//\n// GlobalConstants.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/8/2.\n// Copyright © 2019 Utimes. All"
},
{
"path": "AppStoreDemo/Utils/GlobalFunctions.swift",
"chars": 627,
"preview": "//\n// GlobalFunctions.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/8/2.\n// Copyright © 2019 Utimes. All"
},
{
"path": "AppStoreDemo/Utils/StarView.swift",
"chars": 1484,
"preview": "//\n// StarView.swift\n// AppStoreDemo\n//\n// Created by Allen long on 2019/8/8.\n// Copyright © 2019 Utimes. All rights"
},
{
"path": "AppStoreDemo.xcodeproj/project.pbxproj",
"chars": 45591,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 50;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
},
{
"path": "AppStoreDemo.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:AppStoreDemo.xc"
},
{
"path": "AppStoreDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
"chars": 238,
"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": "AppStoreDemo.xcodeproj/xcuserdata/fengbufang.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist",
"chars": 140,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Bucket\n uuid = \"30E1E68A-18E1-48F7-BC71-4D838AD72221\"\n type = \"1\"\n version"
},
{
"path": "AppStoreDemo.xcodeproj/xcuserdata/fengbufang.xcuserdatad/xcschemes/xcschememanagement.plist",
"chars": 347,
"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": "README.md",
"chars": 1188,
"preview": "# appstore-clone\n\nan awesome clone of iOS App Store.[中文简介](https://github.com/DragonTnT/appstore-clone/blob/master/%E4%B"
},
{
"path": "中文简介.md",
"chars": 353,
"preview": "# appstore-clone\n\n本项目是对iOS中的软件App Store的模仿\n\n\n\n## 介绍\n\nApp Store应该是大家在iphone里最常用的软件之一。作为一名iOS开发者,我一直有模仿App Store的想法。我花了一些业"
}
]
// ... and 3 more files (download for full content)
About this extraction
This page contains the full source code of the DragonTnT/appstore-clone GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 102 files (261.2 KB), approximately 73.7k 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.