Commit 2e432d2c authored by zxhy's avatar zxhy

landing

parent 33c8d786
...@@ -64,7 +64,6 @@ ...@@ -64,7 +64,6 @@
B29A159C241A6A66EFE07177 /* Pods-PhoneManager.debug.xcconfig */, B29A159C241A6A66EFE07177 /* Pods-PhoneManager.debug.xcconfig */,
CC121720387E40164142F3E2 /* Pods-PhoneManager.release.xcconfig */, CC121720387E40164142F3E2 /* Pods-PhoneManager.release.xcconfig */,
); );
name = Pods;
path = Pods; path = Pods;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
...@@ -224,6 +223,7 @@ ...@@ -224,6 +223,7 @@
INFOPLIST_KEY_UIMainStoryboardFile = Main; INFOPLIST_KEY_UIMainStoryboardFile = Main;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
...@@ -253,6 +253,7 @@ ...@@ -253,6 +253,7 @@
INFOPLIST_KEY_UIMainStoryboardFile = Main; INFOPLIST_KEY_UIMainStoryboardFile = Main;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
...@@ -303,7 +304,7 @@ ...@@ -303,7 +304,7 @@
DEBUG_INFORMATION_FORMAT = dwarf; DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES; ENABLE_TESTABILITY = YES;
ENABLE_USER_SCRIPT_SANDBOXING = YES; ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu17; GCC_C_LANGUAGE_STANDARD = gnu17;
GCC_DYNAMIC_NO_PIC = NO; GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES; GCC_NO_COMMON_BLOCKS = YES;
...@@ -366,7 +367,7 @@ ...@@ -366,7 +367,7 @@
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO; ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = YES; ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu17; GCC_C_LANGUAGE_STANDARD = gnu17;
GCC_NO_COMMON_BLOCKS = YES; GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
......
...@@ -9,28 +9,43 @@ import UIKit ...@@ -9,28 +9,43 @@ import UIKit
@main @main
class AppDelegate: UIResponder, UIApplicationDelegate { class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
setupDefault()
window = UIWindow(frame: UIScreen.main.bounds)
window?.backgroundColor = UIColor.colorWithHex(hexStr: launchColor)
let Ssoryboard = UIStoryboard(name: "LauchVC", bundle: nil)
if let current = Ssoryboard.instantiateViewController(identifier: "LauchVCID") as? LauchVC {
window?.rootViewController = current
window?.makeKeyAndVisible()
}
return true return true
} }
// MARK: UISceneSession Lifecycle
private func setupDefault() {
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
// Called when a new scene session is being created. if #available(iOS 13.0, *) {
// Use this method to select a configuration to create the new scene with.
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) let window = UIApplication.shared.windows.first
let topPadding = window?.safeAreaInsets.top ?? 0
statusBarHeight = topPadding > 0 ? topPadding:20
}else {
statusBarHeight = UIApplication.shared.statusBarFrame.size.height
}
} }
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
} }
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "img_guide_02.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "img_guide_02@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "img_guide_02@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "img_icloud_start.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "img_icloud_start@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "img_icloud_start@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "img_photos_start.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "img_photos_start@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "img_photos_start@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "home_pay_close.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "home_pay_close@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "home_pay_close@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8"?>
<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"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies> <dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/> <capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies> </dependencies>
...@@ -11,15 +12,31 @@ ...@@ -11,15 +12,31 @@
<objects> <objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController"> <viewController id="01J-lp-oVM" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3"> <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/> <rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" xcode11CocoaTouchSystemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/> <subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="img_star_start_2.png" translatesAutoresizingMaskIntoConstraints="NO" id="Whq-17-MfS">
<rect key="frame" x="86.333333333333329" y="305.66666666666669" width="188.33333333333337" height="188.66666666666669"/>
<constraints>
<constraint firstAttribute="width" secondItem="Whq-17-MfS" secondAttribute="height" multiplier="1:1" id="KvZ-kq-6Du"/>
</constraints>
</imageView>
</subviews>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/> <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
<color key="backgroundColor" red="0.0" green="0.50980392156862742" blue="1" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstItem="Whq-17-MfS" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" constant="-26" id="eUc-AI-tgC"/>
<constraint firstItem="Whq-17-MfS" firstAttribute="width" secondItem="Ze5-6b-2t3" secondAttribute="width" multiplier="0.48" id="yGe-jC-RdK"/>
<constraint firstItem="Whq-17-MfS" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" constant="-16" id="zVN-dN-0aT"/>
</constraints>
</view> </view>
</viewController> </viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/> <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects> </objects>
<point key="canvasLocation" x="53" y="375"/> <point key="canvasLocation" x="52.671755725190835" y="374.64788732394368"/>
</scene> </scene>
</scenes> </scenes>
<resources>
<image name="img_star_start_2.png" width="360" height="360"/>
</resources>
</document> </document>
//
// BaseNavViewController.swift
// PhoneManager
//
// Created by zxhy on 2025/3/19.
//
import UIKit
class BaseNavViewController:UINavigationController ,UIGestureRecognizerDelegate {
var barStatyl:UIStatusBarStyle = .darkContent {
didSet {
self.setNeedsStatusBarAppearanceUpdate()
}
}
var barHidden:Bool = false {
didSet {
self.setNeedsStatusBarAppearanceUpdate()
}
}
enum AnimationType {
case def
case recectToFull
case overRightToLeft
case overBottomToTop
case dissRight
}
enum PushAnimationType {
case normal
case diy
case bottomToTop
case book
}
var isAnimation:AnimationType
var cIsPopGestureRecognizer:Bool
var cPushAnimation:PushAnimationType
init(isAnimation:AnimationType = .def,rootViewController:UIViewController,isPopGestureRecognizer:Bool = true,pushAnimation:PushAnimationType = .normal) {
self.isAnimation = isAnimation
self.cIsPopGestureRecognizer = isPopGestureRecognizer
self.cPushAnimation = pushAnimation
super.init(rootViewController: rootViewController)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
}
func setupUI() {
navigationBar.isHidden = true
self.delegate = self
interactivePopGestureRecognizer?.delegate = self
if isAnimation != .def {
self.transitioningDelegate = self
}else {
self.transitioningDelegate = nil
}
}
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
if !cIsPopGestureRecognizer {
return false
}
if children.count == 1 {
return false
}else {
return true
}
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
func UMPCheck() {
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return barStatyl
}
override var prefersStatusBarHidden:Bool {
return barHidden
}
func pushViewController(_ viewController: UIViewController, animated: Bool,pushAnimationType:PushAnimationType) {
cPushAnimation = pushAnimationType
super.pushViewController(viewController, animated: animated)
}
deinit {
NotificationCenter.default.removeObserver(self)
}
}
extension BaseNavViewController:UIViewControllerTransitioningDelegate {
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return nil
}
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return nil
}
}
extension BaseNavViewController:UINavigationControllerDelegate {
func navigationController(_ navigationController: UINavigationController,
animationControllerFor operation: UINavigationController.Operation,
from fromVC: UIViewController,
to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return nil
}
}
{"v":"5.7.4","fr":30,"ip":20,"op":71,"w":245,"h":30,"nm":"CL_Onboarding_Full_LIGHT","ddd":0,"assets":[{"id":"comp_0","layers":[{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 3","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[375,743,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[491,60],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":1224,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.098039223166,0.117647066303,0.227450995352,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-0.5,95],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":102,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 2","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":20,"s":[-116,743,0],"to":[81.833,0,0],"ti":[-81.833,0,0]},{"t":70,"s":[375,743,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[491,60],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":1224,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"gf","o":{"a":0,"k":100,"ix":10},"r":1,"bm":0,"g":{"p":3,"k":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":20,"s":[0,0.539,0.804,0.571,0.5,0.458,0.865,0.481,1,0.377,0.925,0.391]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":58,"s":[0,0.929,0.69,0.722,0.5,0.922,0.402,0.418,1,0.914,0.114,0.114]},{"t":70,"s":[0,0.929,0.69,0.722,0.5,0.922,0.402,0.418,1,0.914,0.114,0.114]}],"ix":9}},"s":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":20,"s":[211,0],"to":[-76.333,0],"ti":[76.333,0]},{"t":70,"s":[-247,0]}],"ix":5},"e":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":20,"s":[247,2],"to":[-1.167,0],"ti":[1.167,0]},{"t":70,"s":[240,2]}],"ix":6},"t":1,"nm":"Gradient Fill 1","mn":"ADBE Vector Graphic - G-Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-0.5,95],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":102,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[375,743,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[491,60],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":1224,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.937254901961,0.956862745098,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-0.5,95],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":102,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"CL_Onboarding_Page_01","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[122.5,2,0],"ix":2,"l":2},"a":{"a":0,"k":[375,812,0],"ix":1,"l":2},"s":{"a":0,"k":[50,50,100],"ix":6,"l":2}},"ao":0,"w":750,"h":1624,"ip":0,"op":90,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
//
// HomeViewController.swift
// PhoneManager
//
// Created by zxhy on 2025/3/19.
//
import UIKit
class HomeViewController:UIViewController {
private var isShowPay:Bool = false
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .green
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if !isShowPay {
isShowPay = true
let vc:HomePayViewController = HomePayViewController()
let nav:BaseNavViewController = BaseNavViewController(rootViewController: vc)
nav.modalPresentationStyle = .fullScreen
self.navigationController?.present(nav, animated: true)
}
}
}
This diff is collapsed.
//
// LandingVC.swift
// PhoneManager
//
// Created by zxhy on 2025/3/19.
//
import UIKit
class LandingVC:UIViewController {
@IBOutlet weak var titleBackView: UIView!
@IBOutlet weak var bottomTextView: UITextView!
@IBOutlet weak var nextButton: UIButton!
@IBOutlet weak var bottomView: UIView!
private var currentIndex:Int = 0
private var collectionView: UICollectionView?
private var titleAnimationView:LandingTitleAnimationView?
private var models:[LandingCollectionModel] = []
override func viewDidLoad() {
super.viewDidLoad()
setDefault()
configureGradientView()
setupUI()
}
private func setDefault() {
models = loadLandingSONFromBundle() ?? []
}
private func setupUI() {
titleAnimationView = LandingTitleAnimationView(frame: titleBackView.bounds, count: models.count, spacing: 12)
titleBackView.addSubview(titleAnimationView ?? UIView())
titleAnimationView?.startWithIndex(index: currentIndex)
titleAnimationView?.callBack = {[weak self] index in
guard let self else {return}
let nextIndex = (index as? Int ?? 0) + 1
changeCurrentIndex(index: nextIndex)
}
bottomTextView.isEditable = false
bottomTextView.isScrollEnabled = false
bottomTextView.backgroundColor = .clear
bottomTextView.delegate = self
let fullText = "Privacy Policy and Terms of Use"
let termsText = "Terms of Use"
let privacyText = "Privacy Policy"
let attributedString2 = NSMutableAttributedString(string: fullText, attributes: [
.font: UIFont.systemFont(ofSize: 14),
.foregroundColor: UIColor.colorWithHex(hexStr: "#666666")
])
let termsRange = (fullText as NSString).range(of: termsText)
let privacyRange = (fullText as NSString).range(of: privacyText)
attributedString2.addAttributes([
.underlineStyle: NSUnderlineStyle.single.rawValue,
.link:"terms://termsOfUse"
], range: termsRange)
attributedString2.addAttributes([
.underlineStyle: NSUnderlineStyle.single.rawValue,
.link: "privacy://privacyPolicy"
], range: privacyRange)
bottomTextView.gestureRecognizers?.forEach { gestureRecognizer in
if gestureRecognizer is UILongPressGestureRecognizer {
// 移除长按手势
bottomTextView.removeGestureRecognizer(gestureRecognizer)
}
}
bottomTextView.gestureRecognizers?.forEach { gestureRecognizer in
if gestureRecognizer is UILongPressGestureRecognizer {
// 禁用长按和双击手势
gestureRecognizer.isEnabled = false
}
if let tapGesture = gestureRecognizer as? UITapGestureRecognizer {
// 判断是否是双击手势
if tapGesture.numberOfTapsRequired == 2 {
tapGesture.isEnabled = false // 禁用双击手势
}
}
}
bottomTextView.attributedText = attributedString2
bottomTextView.textAlignment = .center
bottomTextView.linkTextAttributes = [:] // 取消默认 link 颜
nextButton.titleLabel?.font = UIFont.systemFont(ofSize: 16, weight: .bold)
let cW:CGFloat = view.width
let cY:CGFloat = titleBackView.y + titleBackView.height
let cH:CGFloat = bottomView.y - cY
let flowlayout:UICollectionViewFlowLayout = UICollectionViewFlowLayout()
flowlayout.scrollDirection = .horizontal
flowlayout.itemSize = CGSizeMake(cW, cH)
flowlayout.minimumLineSpacing = 0
collectionView = UICollectionView.init(frame: CGRectMake(0, cY , cW , cH), collectionViewLayout: flowlayout)
collectionView?.backgroundColor = .clear
collectionView?.decelerationRate = UIScrollView.DecelerationRate.fast;
collectionView?.showsHorizontalScrollIndicator = false
collectionView?.showsVerticalScrollIndicator = false
collectionView?.isPagingEnabled = true
collectionView?.isUserInteractionEnabled = false
let nib = UINib(nibName: "LandingCollectionCell", bundle: nil)
collectionView?.register(nib, forCellWithReuseIdentifier: LandingCollectionCell.identifiers)
// 设置 UICollectionView 的数据源和代理
collectionView?.dataSource = self
collectionView?.delegate = self
view.addSubview(collectionView!)
}
func findCell(at indexPath: IndexPath) -> LandingCollectionCell? {
return collectionView?.cellForItem(at: indexPath) as? LandingCollectionCell ?? nil
}
private func configureGradientView() {
// 创建 CAGradientLayer
let gradientLayer = CAGradientLayer()
// 设置渐变的颜色
gradientLayer.colors = [
UIColor.colorWithHex(hexStr: "#FFFFFF").cgColor, // 白色
UIColor.colorWithHex(hexStr: "#E4EDFD").cgColor // 浅蓝色
]
// 设置渐变方向(从上到下)
gradientLayer.startPoint = CGPoint(x: 0.5, y: 0.0) // 顶部
gradientLayer.endPoint = CGPoint(x: 0.5, y: 1.0) // 底部
// 设置渐变图层的大小
gradientLayer.frame = view.bounds
// 将渐变图层添加到视图中
view.layer.insertSublayer(gradientLayer, at: 0)
}
@IBAction func nextClick(_ sender: UIButton) {
changeCurrentIndex(index: currentIndex + 1)
sender.titleLabel?.font = UIFont.systemFont(ofSize: 16, weight: .bold)
}
private func changeCurrentIndex(index:Int) {
if (index < models.count) {
currentIndex = index
let indexPath = IndexPath(item: index, section: 0)
DispatchQueue.main.async {[weak self] in
guard let self else {return}
titleAnimationView?.startWithIndex(index: index)
collectionView?.scrollToItem(at: indexPath , at: UICollectionView.ScrollPosition.left, animated: true)
findCell(at: indexPath)?.playAnimation()
if (index == models.count - 1) {
nextButton.setTitle("Get started", for: .normal)
}else {
nextButton.setTitle("Next", for: .normal)
}
}
}else {
let vc:HomeViewController = HomeViewController()
let nav = BaseNavViewController(rootViewController: vc)
cWindow?.rootViewController = nav
let transition = CATransition()
transition.duration = 0.5
transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
// 添加动画到 window 的 layer
cWindow?.layer.add(transition, forKey: kCATransition)
// 显示 window
cWindow?.makeKeyAndVisible()
}
}
}
extension LandingVC:UITextViewDelegate {
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
if URL.scheme == "terms" {
print("Terms of Use 点击事件")
// 处理 Terms of Use 点击事件
return false // 阻止默认行为(打开链接)
} else if URL.scheme == "privacy" {
print("Privacy Policy 点击事件")
// 处理 Privacy Policy 点击事件
return false // 阻止默认行为(打开链接)
}
return true
}
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
// 禁用所有菜单选项
return false
}
}
extension LandingVC:UICollectionViewDataSource,UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return models.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: LandingCollectionCell.identifiers, for: indexPath) as! LandingCollectionCell
if (indexPath.row < models.count) {
cell.model = models[indexPath.row]
}
return cell
}
}
//
// LandingCollectionModel.swift
// PhoneManager
//
// Created by zxhy on 2025/3/20.
//
import Foundation
func loadLandingSONFromBundle() -> [LandingCollectionModel]? {
// 获取 JSON 文件路径
guard let path = Bundle.main.path(forResource: "LandingData", ofType: "json") else {
print("未找到 JSON 文件")
return nil
}
do {
// 读取文件内容
let data = try Data(contentsOf: URL(fileURLWithPath: path))
// 解析 JSON 数据
let decoder = JSONDecoder()
let items = try decoder.decode([LandingCollectionModel].self, from: data)
return items
} catch {
print("解析 JSON 失败:\(error)")
return nil
}
}
struct LandingCollectionModel:Codable {
var title:String
var tip:String
var tipKey:String
var animation:String
enum Category: String, Codable {
case title,tip,tipKey,animation
}
}
[
{
"title": "More Storage Space",
"tip": "+80% extra space for all your mediawith Cleanup",
"tipKey":"+80%",
"animation": "increaseSpaceLight"
},
{
"title": "Eliminate Duplicates",
"tip": "180 duplicate contacts removed on average",
"tipKey":"180",
"animation": "removeDuplicatesLight"
},
{
"title": "Save Hours",
"tip": "9 hours gained per month with automated clean-ups",
"tipKey":"9 hours",
"animation": "maximizeYourTimeLight"
}
]
This diff is collapsed.
//
// PermissionViewController.swift
// PhoneManager
//
// Created by zxhy on 2025/3/19.
//
import UIKit
import Lottie
import Foundation
class PermissionVC:UIViewController {
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var animationBackView: UIView!
@IBOutlet weak var tipLabel: UILabel!
@IBOutlet weak var bottomTextView: UITextView!
@IBOutlet weak var nextButton: UIButton!
lazy var animationView:LottieAnimationView = {
let animationView = LottieAnimationView(name: "onboardingStorageLight")
animationView.play(fromProgress: 0.0, toProgress: 0.7, loopMode: .playOnce) { finished in
print("Animation finished at 80%")
}
return animationView
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
setupUI()
}
func setupUI() {
titleLabel.font = UIFont.systemFont(ofSize: 24, weight: .bold)
titleLabel.textColor = UIColor.colorWithHex(hexStr: black3Color)
titleLabel.width = 183
titleLabel.numberOfLines = 2
titleLabel.text = "Welcome to Cleanup"
// 创建 NSMutableAttributedString
titleLabel.setlineSpacing(font: titleLabel.font, lineSpacing: 8,width: titleLabel.width,numberOfLines: 2, content: titleLabel.text ?? "")
titleLabel.textAlignment = .center
titleLabel.centerX = view.width / 2
animationView.frame = animationBackView.bounds
animationBackView.addSubview(animationView)
tipLabel.font = UIFont.systemFont(ofSize: 20, weight: .medium) // 设置字体大小和粗体
tipLabel.textAlignment = .center // 设置对齐方式(可选)
// 创建 NSAttributedString
let text = "? of 64 GB used"
let attributedString = NSMutableAttributedString(string: text)
// 设置整体颜色为 #333333
attributedString.addAttribute(.foregroundColor, value: UIColor(red: 51/255, green: 51/255, blue: 51/255, alpha: 1.0), range: NSRange(location: 0, length: text.count))
// 设置 "used" 的颜色为 #E73A3A
if let range = text.range(of: "used") {
let nsRange = NSRange(range, in: text)
attributedString.addAttribute(.foregroundColor, value: UIColor(red: 231/255, green: 58/255, blue: 58/255, alpha: 1.0), range: nsRange)
}
// 将 NSAttributedString 赋值给 UILabel
tipLabel.attributedText = attributedString
bottomTextView.isEditable = false
bottomTextView.isScrollEnabled = false
bottomTextView.backgroundColor = .clear
bottomTextView.delegate = self
let fullText = "Cleanup needs access to your Photos to free up storage. We intend to provide transparency and protect your privacy. By starting you accept our Terms of Use and Privacy Policy."
let termsText = "Terms of Use"
let privacyText = "Privacy Policy"
let attributedString2 = NSMutableAttributedString(string: fullText, attributes: [
.font: UIFont.systemFont(ofSize: 14),
.foregroundColor: UIColor.colorWithHex(hexStr: "#666666")
])
let termsRange = (fullText as NSString).range(of: termsText)
let privacyRange = (fullText as NSString).range(of: privacyText)
attributedString2.addAttributes([
.foregroundColor: UIColor.colorWithHex(hexStr: "#0082FF"),
.underlineStyle: NSUnderlineStyle.single.rawValue,
.link:"terms://termsOfUse"
], range: termsRange)
attributedString2.addAttributes([
.foregroundColor: UIColor.colorWithHex(hexStr: "#0082FF"),
.underlineStyle: NSUnderlineStyle.single.rawValue,
.link: "privacy://privacyPolicy"
], range: privacyRange)
bottomTextView.gestureRecognizers?.forEach { gestureRecognizer in
if gestureRecognizer is UILongPressGestureRecognizer {
// 移除长按手势
bottomTextView.removeGestureRecognizer(gestureRecognizer)
}
}
bottomTextView.gestureRecognizers?.forEach { gestureRecognizer in
if gestureRecognizer is UILongPressGestureRecognizer {
// 禁用长按和双击手势
gestureRecognizer.isEnabled = false
}
if let tapGesture = gestureRecognizer as? UITapGestureRecognizer {
// 判断是否是双击手势
if tapGesture.numberOfTapsRequired == 2 {
tapGesture.isEnabled = false // 禁用双击手势
}
}
}
bottomTextView.attributedText = attributedString2
bottomTextView.textAlignment = .center
bottomTextView.linkTextAttributes = [:] // 取消默认 link 颜色
nextButton.titleLabel?.font = UIFont.systemFont(ofSize: 16, weight: .bold)
}
@IBAction func gerstartedClick(_ sender: Any) {
print("click");
let Ssoryboard = UIStoryboard(name: "LandingVC", bundle: nil)
if let current = Ssoryboard.instantiateViewController(identifier: "LandingVCID") as? LandingVC {
self.navigationController?.pushViewController(current, animated: true)
}
}
}
extension PermissionVC: UITextViewDelegate {
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
if URL.scheme == "terms" {
print("Terms of Use 点击事件")
// 处理 Terms of Use 点击事件
return false // 阻止默认行为(打开链接)
} else if URL.scheme == "privacy" {
print("Privacy Policy 点击事件")
// 处理 Privacy Policy 点击事件
return false // 阻止默认行为(打开链接)
}
return true
}
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
// 禁用所有菜单选项
return false
}
}
//
// LandingCollectionCell.swift
// PhoneManager
//
// Created by zxhy on 2025/3/20.
//
import UIKit
import Lottie
class LandingCollectionCell:UICollectionViewCell {
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var tipLabel: UILabel!
private var animationView:LottieAnimationView?
private var backView:UIImageView?
static let identifiers = "LandingCollectionCellID"
var model:LandingCollectionModel? {
didSet {
guard let model else {return}
titleLabel.text = model.title
let fullText = model.tip
// 创建 NSMutableAttributedString
let attributedString = NSMutableAttributedString(string: fullText)
// 设置 "+80%" 的样式
let blueColor = UIColor.colorWithHex(hexStr: mColor)
let largeFont = UIFont.systemFont(ofSize: 28, weight: .bold)
let range1 = (fullText as NSString).range(of: model.tipKey)
attributedString.addAttribute(.foregroundColor, value: blueColor, range: range1)
attributedString.addAttribute(.font, value: largeFont, range: range1)
// 设置其他文本的样式
let darkGrayColor = UIColor.colorWithHex(hexStr: black3Color)
let smallFont = UIFont.systemFont(ofSize: 16, weight: .regular)
let range2 = NSRange(location: range1.length, length: fullText.count - range1.length)
attributedString.addAttribute(.foregroundColor, value: darkGrayColor, range: range2)
attributedString.addAttribute(.font, value: smallFont, range: range2)
backView?.removeFromSuperview()
if (model.animation == "removeDuplicatesLight") {
backView = UIImageView(image: UIImage(named: "img_guide_02"))
contentView.addSubview(backView ?? UIView())
}
// 将 NSAttributedString 赋值给 UILabel
tipLabel.attributedText = attributedString
tipLabel.numberOfLines = 2 // 支持多行
animationView?.removeFromSuperview()
animationView = LottieAnimationView(name: model.animation)
animationView?.loopMode = .playOnce
contentView.addSubview(animationView ?? UIView())
playAnimation()
}
}
override func awakeFromNib() {
super.awakeFromNib()
}
func playAnimation() {
animationView?.play()
}
override func layoutSubviews() {
super.layoutSubviews()
if (model?.animation == "increaseSpaceLight" || model?.animation == "maximizeYourTimeLight") {
animationView?.size = CGSizeMake(258, 258 / 0.9109)
}else if (model?.animation == "removeDuplicatesLight") {
animationView?.size = CGSizeMake(258, 258 / 1.494)
}
animationView?.centerY = (tipLabel.y + tipLabel.height) + (contentView.height - (tipLabel.y + tipLabel.height)) / 2
animationView?.centerX = (contentView.width) / 2
backView?.size = CGSizeMake(286, 288)
backView?.center = animationView?.center ?? CGPointZero
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
<capability name="collection view cell content view" minToolsVersion="11.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" reuseIdentifier="LandingCollectionCellID" id="xoc-GA-iW6" customClass="LandingCollectionCell" customModule="PhoneManager" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="296" height="493"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<collectionViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" id="ZtA-1K-FpE">
<rect key="frame" x="0.0" y="0.0" width="296" height="493"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="J0b-sd-1BF">
<rect key="frame" x="15" y="24" width="266" height="29"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="24"/>
<color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="cjp-Qf-KBq">
<rect key="frame" x="36" y="79" width="224" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="J0b-sd-1BF" secondAttribute="trailing" constant="15" id="20A-PJ-Wll"/>
<constraint firstAttribute="trailing" secondItem="cjp-Qf-KBq" secondAttribute="trailing" constant="36" id="JFf-5Y-xlm"/>
<constraint firstItem="cjp-Qf-KBq" firstAttribute="top" secondItem="J0b-sd-1BF" secondAttribute="bottom" constant="26" id="Jl2-rs-70n"/>
<constraint firstItem="cjp-Qf-KBq" firstAttribute="leading" secondItem="ZtA-1K-FpE" secondAttribute="leading" constant="36" id="Jqs-Yi-IHD"/>
<constraint firstItem="J0b-sd-1BF" firstAttribute="top" secondItem="ZtA-1K-FpE" secondAttribute="top" constant="24" id="XJz-e1-J6Z"/>
<constraint firstItem="J0b-sd-1BF" firstAttribute="leading" secondItem="ZtA-1K-FpE" secondAttribute="leading" constant="15" id="n7s-NT-Nyg"/>
</constraints>
</collectionViewCellContentView>
<size key="customSize" width="296" height="493"/>
<connections>
<outlet property="tipLabel" destination="cjp-Qf-KBq" id="mPC-Rx-B5w"/>
<outlet property="titleLabel" destination="J0b-sd-1BF" id="sKC-cx-qzp"/>
</connections>
<point key="canvasLocation" x="218.32061068702288" y="143.3098591549296"/>
</collectionViewCell>
</objects>
</document>
//
// LandingTitleAnimationView.swift
// PhoneManager
//
// Created by zxhy on 2025/3/20.
//
import UIKit
class LandingTitleAnimationView:UIView {
private var count :Int = 0
private var spacing :CGFloat = 0
private var listAnimationView:[LandingTitleAnimationListView] = []
private var currentCount:Int = 0
var callBack: callBack<Any> = {index in}
init(frame: CGRect,count:Int,spacing:CGFloat) {
self.count = count
self.spacing = spacing
super.init(frame: frame)
addViews()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupUI () {
}
private func addViews () {
let cW:CGFloat = (self.width - CGFloat(count - 1) * spacing) / CGFloat(count)
let cH:CGFloat = self.height
for i in 0..<count {
let subView:LandingTitleAnimationListView = LandingTitleAnimationListView(frame: CGRect(x: CGFloat(i) * (cW + spacing), y: 0, width: cW, height: cH))
self.addSubview(subView)
listAnimationView.append(subView)
}
}
func startWithIndex(index:Int) {
if index < listAnimationView.count {
let subView:LandingTitleAnimationListView = listAnimationView[index]
subView.startAnimation(endAnimation: {[weak self] status in
guard let self else {return}
if (status as? AnimationStatus == AnimationStatus.end) {
self.callBack(index)
}
})
}
for (i,view) in listAnimationView.enumerated() {
if (i < index) {
view.changeIsEnd()
}
}
}
}
class LandingTitleAnimationListView:UIView {
private var colorView:UIView?
private var allColorView:UIView?
private var isEnd:Bool = false
override init(frame: CGRect) {
super.init(frame: frame)
setupUI()
addViews()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupUI () {
self.backgroundColor = UIColor.colorWithHex(hexStr: "#F0F2F5")
self.layer.cornerRadius = self.height / 2 // 圆角半径
self.layer.masksToBounds = true
self.colorView = UIView(frame: self.bounds)
colorView?.backgroundColor = UIColor.colorWithHex(hexStr: mColor)
colorView?.layer.cornerRadius = self.height / 2 // 圆角半径
colorView?.layer.masksToBounds = true
colorView?.width = 0
self.allColorView = UIView(frame: self.bounds)
allColorView?.backgroundColor = UIColor.colorWithHex(hexStr: mColor)
allColorView?.layer.cornerRadius = self.height / 2 // 圆角半径
allColorView?.layer.masksToBounds = true
}
private func addViews () {
addSubview(colorView ?? UIView())
}
func startAnimation(endAnimation:@escaping callBack<Any> = {text in}) {
UIView.animate(withDuration: 4) {[weak self] in
guard let self else {return}
if (!isEnd) {
self.colorView?.width = self.width
}
} completion: {[weak self] Bool in
guard let self else {return}
if (!isEnd) {
isEnd = true
endAnimation(AnimationStatus.end)
}
}
}
func changeIsEnd() {
isEnd = true
self.addSubview(self.allColorView!)
self.colorView?.width = self.width
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="Y6W-OH-hqX">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--LauchVC-->
<scene sceneID="s0d-6b-0kx">
<objects>
<viewController storyboardIdentifier="LauchVCID" id="Y6W-OH-hqX" customClass="LauchVC" customModule="PhoneManager" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="5EZ-qb-Rvc">
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="In6-Ib-vMq">
<rect key="frame" x="0.0" y="0.33333333333331439" width="393" height="851.33333333333348"/>
<constraints>
<constraint firstAttribute="width" secondItem="In6-Ib-vMq" secondAttribute="height" multiplier="0.4618" id="pro-at-5R5"/>
</constraints>
</view>
</subviews>
<viewLayoutGuide key="safeArea" id="vDu-zF-Fre"/>
<color key="backgroundColor" red="0.0" green="0.50980392156862742" blue="1" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstItem="In6-Ib-vMq" firstAttribute="centerX" secondItem="5EZ-qb-Rvc" secondAttribute="centerX" id="Chj-38-1sF"/>
<constraint firstItem="In6-Ib-vMq" firstAttribute="width" secondItem="5EZ-qb-Rvc" secondAttribute="width" id="YGg-mA-X9M"/>
<constraint firstItem="In6-Ib-vMq" firstAttribute="centerY" secondItem="5EZ-qb-Rvc" secondAttribute="centerY" id="ZB8-n3-NkT"/>
</constraints>
</view>
<connections>
<outlet property="backView" destination="In6-Ib-vMq" id="trJ-ol-mah"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Ief-a0-LHa" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="54.198473282442748" y="-34.507042253521128"/>
</scene>
</scenes>
</document>
//
// LauchVC.swift
// PhoneManager
//
// Created by zxhy on 2025/3/19.
//
import UIKit
import Lottie
class LauchVC:UIViewController {
@IBOutlet weak var backView: UIView!
lazy var LaunchingView:LottieAnimationView = {
let animationView = LottieAnimationView(name: "applicationLauncher")
animationView.loopMode = .loop
animationView.play()
return animationView
}()
override func viewDidLoad() {
super.viewDidLoad()
LaunchingView.frame = backView.bounds
backView.addSubview(LaunchingView)
DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: {
var vc:UIViewController?
if (UserDef.shard.isShowLanding) {
vc = HomeViewController()
}else {
let Ssoryboard = UIStoryboard(name: "PermissionVC", bundle: nil)
if let current = Ssoryboard.instantiateViewController(identifier: "PermissionVCID") as? PermissionVC {
vc = current
}
UserDef.shard.isShowLanding = true
UserDef.shard.saveUserDefToSandBox()
}
guard let vc else {return}
let nav = BaseNavViewController(rootViewController: vc)
cWindow?.rootViewController = nav
let transition = CATransition()
transition.duration = 0.5
// transition.type = CATransitionType.push // 推入动画
transition.subtype = CATransitionSubtype.fromRight // 从左侧推入
transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
// 添加动画到 window 的 layer
cWindow?.layer.add(transition, forKey: kCATransition)
// 显示 window
cWindow?.makeKeyAndVisible()
})
}
}
//
// HomePayView.swift
// PhoneManager
//
// Created by zxhy on 2025/3/20.
//
import UIKit
import SnapKit
import Lottie
class HomePayView:UIView {
private var restoreBtn:UIButton?
private var closeBtn:UIButton?
private var titleLabel1:UILabel?
private var titleLabel2:UILabel?
private var photoImage:UIImageView?
private var icloudImage:UIImageView?
private var photoLabel:UILabel?
private var icloudLabel:UILabel?
private var contentView1:UIView?
lazy var animationView:LottieAnimationView = {
let animationView = LottieAnimationView(name: "onboardingStorageLight")
animationView.animationSpeed = -1.0
return animationView
}()
var callBack:callBack<Any> = {text in}
override init(frame: CGRect) {
super.init(frame: frame)
setupUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupUI() {
backgroundColor = .white
restoreBtn = UIButton()
restoreBtn?.setTitle("Restore Purchase", for: .normal)
restoreBtn?.setTitleColor(UIColor.colorWithHex(hexStr: "#B3B3B3"), for: .normal)
restoreBtn?.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .regular)
self.addSubview(restoreBtn!)
restoreBtn?.snp.makeConstraints { make in
make.top.equalToSuperview().offset(statusBarHeight + 20)
make.left.equalToSuperview().offset(15)
}
// 确保按钮大小自适应
restoreBtn?.sizeToFit()
closeBtn = UIButton()
closeBtn?.setImage(UIImage(named: "home_pay_close"), for: .normal)
closeBtn?.addTarget(self, action: #selector(closeBtnClick), for: .touchUpInside)
self.addSubview(closeBtn!)
closeBtn?.snp.makeConstraints { make in
make.centerY.equalTo(restoreBtn!)
make.right.equalToSuperview().offset(-15)
make.width.height.equalTo(28)
}
titleLabel1 = UILabel()
titleLabel1?.text = "Clean your Storage"
titleLabel1?.font = UIFont.systemFont(ofSize: 24, weight: .bold)
titleLabel1?.textColor = UIColor.colorWithHex(hexStr: black3Color)
self.addSubview(titleLabel1!)
titleLabel1?.snp.makeConstraints { make in
make.top.equalToSuperview().offset(statusBarHeight + 68)
make.centerX.equalToSuperview()
}
titleLabel1?.sizeToFit()
titleLabel2 = UILabel()
titleLabel2?.text = "Get rid of what you don't need"
titleLabel2?.font = UIFont.systemFont(ofSize: 14, weight: .bold)
titleLabel2?.textColor = UIColor.colorWithHex(hexStr: black3Color)
self.addSubview(titleLabel2!)
titleLabel2?.snp.makeConstraints { make in
make.top.equalTo(titleLabel1!.snp.bottom).offset(12)
make.centerX.equalToSuperview()
}
titleLabel2?.sizeToFit()
photoImage = UIImageView(image: UIImage(named: "img_photos_start"))
self.addSubview(photoImage!)
photoImage?.snp.makeConstraints { make in
make.top.equalTo(titleLabel2!.snp.bottom).offset(24)
make.centerX.equalToSuperview().offset(-52)
make.width.height.equalTo(64)
}
icloudImage = UIImageView(image: UIImage(named: "img_icloud_start"))
self.addSubview(icloudImage!)
icloudImage?.snp.makeConstraints { make in
make.top.equalTo(titleLabel2!.snp.bottom).offset(24)
make.centerX.equalToSuperview().offset(52)
make.width.height.equalTo(64)
}
photoLabel = UILabel()
photoLabel?.text = "Photos"
photoLabel?.font = UIFont.systemFont(ofSize: 14, weight: .bold)
photoLabel?.textColor = UIColor.colorWithHex(hexStr: black3Color)
self.addSubview(photoLabel!)
photoLabel?.snp.makeConstraints { make in
make.top.equalTo(photoImage!.snp.bottom).offset(16)
make.centerX.equalTo(photoImage!.snp.centerX)
}
photoLabel?.sizeToFit()
icloudLabel = UILabel()
icloudLabel?.text = "iCloud"
icloudLabel?.font = UIFont.systemFont(ofSize: 14, weight: .bold)
icloudLabel?.textColor = UIColor.colorWithHex(hexStr: black3Color)
self.addSubview(icloudLabel!)
icloudLabel?.snp.makeConstraints { make in
make.top.equalTo(icloudImage!.snp.bottom).offset(16)
make.centerX.equalTo(icloudImage!.snp.centerX)
}
icloudLabel?.sizeToFit()
self.addSubview(animationView)
playAnimationWithDelay()
animationView.snp.makeConstraints { make in
make.top.equalTo(photoLabel!.snp.bottom).offset(20)
make.centerX.equalToSuperview()
make.width.equalTo(196.67)
make.height.equalTo(24)
}
contentView1 = UIView()
contentView1?.backgroundColor = UIColor.colorWithHex(hexStr: "#F2F6FC")
self.addSubview(contentView1!)
contentView1?.snp.makeConstraints({ make in
make.top.equalTo(animationView.snp.bottom).offset(76)
make.centerX.equalToSuperview()
make.width.equalToSuperview().offset(-30)
make.height.equalTo(125)
})
contentView1?.layer.cornerRadius = 12
contentView1?.layer.masksToBounds = true
}
func playAnimationWithDelay() {
// 播放动画
animationView.play(fromProgress: 0.4, toProgress: 1, loopMode: .playOnce) {[weak self] finished in
if finished {
// 动画播放完成后,延迟 2 秒再重新播放
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
self?.playAnimationWithDelay()
}
}
}
}
@objc func closeBtnClick() {
callBack(OperStatus.close)
}
}
//
// HomePayView.swift
// PhoneManager
//
// Created by zxhy on 2025/3/20.
//
import UIKit
class HomePayViewController:UIViewController {
private var homePayView:HomePayView?
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
addViews()
}
private func addViews() {
homePayView = HomePayView(frame: view.bounds)
view.addSubview(homePayView!)
homePayView?.callBack = {[weak self] status in
guard let self else {return}
if let operstatus = status as? OperStatus {
switch operstatus {
case .close:
self.navigationController?.dismiss(animated: true)
}
}
}
}
}
//
// Common.swift
// PhoneManager
//
// Created by zxhy on 2025/3/19.
//
import Foundation
//间距
var statusBarHeight:CGFloat = 0
//颜色
let launchColor:String = "#7F33FF"
let mColor:String = "#0082FF"
let blackColor:String = "#000000"
let black3Color:String = "#333333"
//
// CommonFunc.swift
// PhoneManager
//
// Created by zxhy on 2025/3/19.
//
import UIKit
typealias callBack<T> = (T) -> ()
typealias callOperBack = (String) -> ()
let cWindow:UIWindow? = {
if #available(iOS 13, *) {
return UIApplication.shared.connectedScenes
.compactMap { $0 as? UIWindowScene }
.flatMap { $0.windows }
.first(where: { $0.isKeyWindow })
} else {
return UIApplication.shared.keyWindow ?? UIWindow()
}
}()
//
// Status.swift
// PhoneManager
//
// Created by zxhy on 2025/3/20.
//
import Foundation
enum AnimationStatus {
case end
}
enum OperStatus {
case close
}
//
// UserDef.swift
// PhoneManager
//
// Created by zxhy on 2025/3/19.
//
import Foundation
class UserDef:NSObject {
static let shard:UserDef = UserDef()
var isShowLanding:Bool = false
override init() {
let defaults:UserDefaults = UserDefaults.standard
self.isShowLanding = defaults.value(forKey: "isShowLanding") as? Bool ?? false
}
func saveUserDefToSandBox() {
let defaults:UserDefaults = UserDefaults.standard
defaults.setValue(UserDef.shard.isShowLanding, forKey: "isShowLanding")
defaults.synchronize()
}
class func saveKeyWithValue(key:String,value:Any) {
UserDefaults.standard.set(value, forKey: key)
}
}
//
// UIView+Extension.swift
// PhoneManager
//
// Created by zxhy on 2025/3/19.
//
import UIKit
extension UIView {
func responderViewController() -> UIViewController? {
for view in sequence(first: self.superview, next: { $0?.superview }) {
if let responder = view?.next {
if responder.isKind(of: UIViewController.self){
return responder as? UIViewController
}
}
}
return nil
}
func cornerCut(radius:CGFloat,corner:UIRectCorner){
let maskPath = UIBezierPath.init(roundedRect: bounds, byRoundingCorners: corner, cornerRadii: CGSize.init(width: radius, height: radius))
let maskLayer = CAShapeLayer()
maskLayer.frame = bounds
maskLayer.path = maskPath.cgPath
layer.mask = maskLayer
}
func setShadow(
cornerRadius:CGFloat = 4,
sColor:UIColor = UIColor.colorWithHex(hexStr: blackColor, alpha: 0.08),
offset:CGSize = CGSize(width: 0, height: 0),
opacity:Float = 1,
radius:CGFloat = 8
) {
//设置阴影颜色
self.layer.shadowColor = sColor.cgColor
//设置透明度
self.layer.shadowOpacity = opacity
//设置阴影半径
self.layer.shadowRadius = radius
//设置阴影偏移量
self.layer.shadowOffset = offset
//
self.layer.cornerRadius = cornerRadius
}
var x :CGFloat {
get {
return frame.origin.x
}
set {
var frame1:CGRect = frame
frame1.origin.x = newValue
frame = frame1
}
}
var y :CGFloat {
get {
return frame.origin.y
}
set {
var frame1:CGRect = frame
frame1.origin.y = newValue
frame = frame1
}
}
var width :CGFloat {
get {
return frame.size.width
}
set {
var frame1:CGRect = frame
frame1.size.width = newValue
frame = frame1
}
}
var height :CGFloat {
get {
return frame.size.height
}
set {
var frame1:CGRect = frame
frame1.size.height = newValue
frame = frame1
}
}
var size :CGSize {
get {
return frame.size
}
set {
var frame1:CGRect = frame
frame1.size = newValue
frame = frame1
}
}
var centerX :CGFloat {
get {
return center.x
}
set {
var center1:CGPoint = center
center1.x = newValue
center = center1
}
}
var centerY :CGFloat {
get {
return center.y
}
set {
var center1:CGPoint = center
center1.y = newValue
center = center1
}
}
}
//
// UIColor+Extension.swift
// PhoneManager
//
// Created by zxhy on 2025/3/19.
//
import UIKit
extension UIColor {
class func colorWithHex(hexStr:String,alpha:Float = 1) -> UIColor {
var cStr = hexStr.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines).uppercased() as NSString
if(cStr.length < 6) {
return UIColor.clear
}
if(cStr.hasPrefix("0x")) {
cStr = cStr.substring(from: 2) as NSString
}
if(cStr.hasPrefix("#")) {
cStr = cStr.substring(from: 1) as NSString
}
if(cStr.length != 6) {
return UIColor.clear
}
let rStr = (cStr as NSString).substring(to: 2)
let gStr = ((cStr as NSString).substring(from: 2) as NSString).substring(to: 2)
let bStr = ((cStr as NSString).substring(from: 4) as NSString).substring(to: 2)
var r:UInt64 = 0
var g:UInt64 = 0
var b:UInt64 = 0
Scanner.init(string: rStr).scanHexInt64(&r)
Scanner.init(string: gStr).scanHexInt64(&g)
Scanner.init(string: bStr).scanHexInt64(&b)
return UIColor.init(red: CGFloat(r)/255.0, green: CGFloat(g)/255.0, blue: CGFloat(b)/255.0, alpha: CGFloat(alpha))
}
}
//
// UILabel+Extension.swift
// PhoneManager
//
// Created by zxhy on 2025/3/19.
//
import UIKit
extension UILabel {
static func getSizeWith(
font:UIFont = UIFont.systemFont(ofSize: 14, weight: .regular),
lineSpacing:CGFloat = 5 ,
paragraphSpacing:CGFloat = 0,
width:CGFloat = CGFloat(MAXFLOAT),
numberOfLines:Int = 0,
content:String) -> CGSize {
let sview:UILabel = UILabel()
sview.width = width
sview.font = font
sview.numberOfLines = 0
let style = NSMutableParagraphStyle()
style.lineSpacing = lineSpacing
style.paragraphSpacing = paragraphSpacing
sview.attributedText = NSAttributedString(string: content, attributes: [NSAttributedString.Key.paragraphStyle: style])
sview.numberOfLines = numberOfLines
sview.sizeToFit()
return sview.size
}
func setlineSpacing(font:UIFont = UIFont.systemFont(ofSize: 14, weight: .regular),
lineSpacing:CGFloat = 5,
paragraphSpacing:CGFloat = 0,
width:CGFloat = CGFloat(MAXFLOAT),
numberOfLines:Int = 0,
content:String) {
self.width = width
self.font = font
self.numberOfLines = 0
let style = NSMutableParagraphStyle()
style.lineSpacing = lineSpacing
style.paragraphSpacing = paragraphSpacing
self.attributedText = NSAttributedString(string: content, attributes: [NSAttributedString.Key.paragraphStyle: style])
self.numberOfLines = numberOfLines
self.sizeToFit()
self.width = width
}
}
...@@ -6,20 +6,6 @@ ...@@ -6,20 +6,6 @@
<dict> <dict>
<key>UIApplicationSupportsMultipleScenes</key> <key>UIApplicationSupportsMultipleScenes</key>
<false/> <false/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneConfigurationName</key>
<string>Default Configuration</string>
<key>UISceneDelegateClassName</key>
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
<key>UISceneStoryboardFile</key>
<string>Main</string>
</dict>
</array>
</dict>
</dict> </dict>
</dict> </dict>
</plist> </plist>
//
// SceneDelegate.swift
// PhoneManager
//
// Created by zxhy on 2025/3/19.
//
import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
guard let _ = (scene as? UIWindowScene) else { return }
}
func sceneDidDisconnect(_ scene: UIScene) {
// Called as the scene is being released by the system.
// This occurs shortly after the scene enters the background, or when its session is discarded.
// Release any resources associated with this scene that can be re-created the next time the scene connects.
// The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
}
func sceneDidBecomeActive(_ scene: UIScene) {
// Called when the scene has moved from an inactive state to an active state.
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
}
func sceneWillResignActive(_ scene: UIScene) {
// Called when the scene will move from an active state to an inactive state.
// This may occur due to temporary interruptions (ex. an incoming phone call).
}
func sceneWillEnterForeground(_ scene: UIScene) {
// Called as the scene transitions from the background to the foreground.
// Use this method to undo the changes made on entering the background.
}
func sceneDidEnterBackground(_ scene: UIScene) {
// Called as the scene transitions from the foreground to the background.
// Use this method to save data, release shared resources, and store enough scene-specific state information
// to restore the scene back to its current state.
}
}
...@@ -12,6 +12,8 @@ class ViewController: UIViewController { ...@@ -12,6 +12,8 @@ class ViewController: UIViewController {
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
// Do any additional setup after loading the view. // Do any additional setup after loading the view.
view.backgroundColor = .green
} }
......
...@@ -7,5 +7,7 @@ target 'PhoneManager' do ...@@ -7,5 +7,7 @@ target 'PhoneManager' do
# Pods for PhoneManager # Pods for PhoneManager
pod 'Alamofire' pod 'Alamofire'
pod 'lottie-ios'
pod 'SnapKit'
end end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment