美文网首页
Swift小demo学习笔记

Swift小demo学习笔记

作者: 黑化肥发灰 | 来源:发表于2017-07-26 09:33 被阅读76次

    之前看了一些swift相关的介绍,但是一直没怎么写代码,但是不写代码肯定掌握不好一门语言的,纸上得来终觉浅,绝知此事要躬码。正好在github上找到了一个好东西,有三四十个小demo,我决定参考他们自己重写一遍了。本篇笔记记录下每个demo里面自己不熟的地方,后面可以随时复习。
    参考链接如下:SwiftPractice

    1.GHWSimpleClock

        func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
            self.window = UIWindow(frame: CGRect(x: 0, y: 0, width: kScreenWidth, height: kScreenHeight))
            let vc = GHWViewController()
            self.window?.rootViewController = vc
            self.window?.makeKeyAndVisible()
            return true
    
        }
    
        [self.buttonLeft, self.buttonRight].forEach {
            ($0.addTarget(self, action: #selector(buttonTap(sender:)), for: .touchUpInside))
        }
    
        func buttonTap(sender : UIButton) {
            switch sender {
            case self.buttonLeft:
                sender.isSelected = !sender.isSelected
                sender.isSelected ? start() : stop()
                break
            case self.buttonRight:
                sender.isSelected = !sender.isSelected
                sender.isSelected ? pause() : continue1()
                break
            default:
                return
            }
        }
    

    2. GHWCustomFont

    return tableViewHeight/CGFloat(dataArray.count)
    
    //设置状态栏样式
    /*设置状态栏:
     @available(iOS 7.0, *)
     open var preferredStatusBarStyle: UIStatusBarStyle { get }//样式
     
     @available(iOS 7.0, *)
     open var prefersStatusBarHidden: Bool { get }//是否隐藏
    */
    override var preferredStatusBarStyle: UIStatusBarStyle {
        return .lightContent
    }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            /*代码创建,并且没有注册cell的情况下,用dequeueReusableCell(withIdentifier identifier: String) -> UITableViewCell?
             如果已经注册了,或者用的xib,就使用dequeueReusableCell(withIdentifier identifier: String, for indexPath: IndexPath) -> UITableViewCell
             */
            //??空合运算符,a ?? b,对可选类型a进行判断,为nil默认值为b,不为空就解封
            let cell = tableView.dequeueReusableCell(withIdentifier: reuseIdentifier) ?? UITableViewCell(style: .subtitle, reuseIdentifier: reuseIdentifier)
            let text = datas[indexPath.row]
            
            cell.textLabel?.text = text
            cell.textLabel?.textColor = .white
            cell.textLabel?.font = UIFont(name: fontNames[fontNumber], size: 24)
            cell.backgroundColor = .black
            
            return cell
        }
    
    

    3. PlayLocalVideo

    struct VideoModel {
        let image: String
        let title: String
        let source: String
    }
    
    // 不加问号的话会报错:class has no initializers, 这里凡是没有初始化的都要加上问号
    var player : AVPlayer?
    var playerViewController : AVPlayerViewController?
    
        let dataArray = [
            VideoModel(image: "videoScreenshot01", title: "Introduce 3DS Mario", source: "Youtube - 06:32"),
            VideoModel(image: "videoScreenshot02", title: "Emoji Among Us", source: "Vimeo - 3:34"),
            VideoModel(image: "videoScreenshot03", title: "Seals Documentary", source: "Vine - 00:06"),
            VideoModel(image: "videoScreenshot04", title: "Adventure Time", source: "Youtube - 02:39"),
            VideoModel(image: "videoScreenshot05", title: "Facebook HQ", source: "Facebook - 10:20"),
            VideoModel(image: "videoScreenshot06", title: "Lijiang Lugu Lake", source: "Allen - 20:30")
        ]
    

    4. WelcomeView

            //遍历数组,同时获得index
            for (index,value) in images.enumerated() {
                let imageView = UIImageView(frame: CGRect(x: YHWidth*CGFloat(index), y: 0, width: YHWidth, height: YHHeight))
                imageView.image = UIImage(named: value)
                //限制边界
                imageView.clipsToBounds = true
                imageView.contentMode = .scaleAspectFill
                scrollBG.addSubview(imageView)
            }
    

    5. PictureBrowse

    // 毛玻璃
        let blurView = UIVisualEffectView(effect: UIBlurEffect(style: .light))
    
        let myLayout = UICollectionViewFlowLayout()
        myLayout.scrollDirection = .horizontal
        myLayout.itemSize = CGSize(width: kCellWidth, height: kCellHeight)
        myLayout.minimumLineSpacing = 20
        myLayout.minimumInteritemSpacing = 20
        myLayout.sectionInset = UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 0)
        
        collectionView = UICollectionView(frame: CGRect(x : 0, y : (kScreenHeight - kCellHeight)/2, width : kScreenWidth, height : kCellHeight), collectionViewLayout: myLayout)
        collectionView.delegate = self;
        collectionView.dataSource = self;
        collectionView.backgroundColor = .clear
        collectionView.register(GHWCollectionViewCell.self, forCellWithReuseIdentifier: identifier)
    
        var data: CollectionModel? {
            /*属性观察器
             willSet 在新的值被设置之前调用
             didSet 在新的值被设置之后立即调用
             */
            didSet {
                updateUI()
            }
        }
        private func updateUI() {
            featureImageView.image = data?.featuredImage
            interestTitleLabel.text = data?.title
            interestDetailLabel.text = data?.descriptions
        }
    
    
    static func createInterests() -> [CollectionModel] {
        return [
            CollectionModel(title: "Training like this, #bodyline", descriptions: "Create beautiful apps. We walked to Antartica yesterday, and camped with some cute pinguines, and talked about this wonderful app idea. 🐧⛺️✨", featuredImage: UIImage(named: "bodyline")!)
        ]
    }
    
        var title: String?
        var featureImage: UIImage?
        var descriptions: String?
        
        // 这边不需要override,只有真正敲代码才能知道这些问题了,所以删掉
        init(title: String, descriptions: String, featureImage: UIImage) {
            self.featureImage = featureImage
            self.title = title
            self.descriptions = descriptions
        }
    
    

    6. Current Location


    下面这样是好的:


    7. SystemRefreshControl

        let newData = ["1111", "2222", "3333", "4444"]
        var dataArray = ["11", "22", "33", "44"]
        let identifier = "identifier"
        func addData() {
            dataArray.append(contentsOf: newData)
            tableView.reloadData()
            refreshControl.endRefreshing()
        }
    

    8 GradientColor

    import UIKit
    let YHRect = UIScreen.main.bounds
    let YHHeight = YHRect.size.height
    let YHWidth = YHRect.size.width
    class ViewController: UIViewController {
        let gradientLayer = CAGradientLayer()
        override func viewDidLoad() {
            super.viewDidLoad()
            setupView()
        }
        override var preferredStatusBarStyle: UIStatusBarStyle {
            return .lightContent
        }
        func setupView() {
            setupGradientLayer()
            Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(randomColor), userInfo: nil, repeats: true)
        }
        func setupGradientLayer() {
            gradientLayer.frame = YHRect
            let color1 = UIColor(white: 0.5, alpha: 0.2).cgColor
            let color2 = UIColor(red: 1.0, green: 0, blue: 0, alpha: 0.4).cgColor
            let color3 = UIColor(red: 0, green: 1, blue: 0, alpha: 0.3).cgColor
            let color4 = UIColor(red: 0, green: 0, blue: 1, alpha: 0.3).cgColor
            let color5 = UIColor(white: 0.4, alpha: 0.2).cgColor
            gradientLayer.colors = [color1, color2, color3, color4, color5]
            gradientLayer.locations = [0.10, 0.30, 0.50, 0.70, 0.90]
            gradientLayer.startPoint = CGPoint(x: 0, y: 0)
            gradientLayer.endPoint = CGPoint(x: 1, y: 1)
            view.layer.addSublayer(gradientLayer)
        }
        func randomColor() {
            view.backgroundColor = UIColor(red: CGFloat(drand48()), green: CGFloat(drand48()), blue: CGFloat(drand48()), alpha: 1.0)
        }
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Dispose of any resources that can be recreated.
        }
    }
    

    9. GradientColor

    import UIKit
    
    class GHWMainViewController: UIViewController, UIScrollViewDelegate {
    
        let bottomView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
        let scrollView = UIScrollView(frame: kScreenRect)
        let imageView = UIImageView(image: UIImage(named: "steve"))
        override func viewDidLoad() {
            super.viewDidLoad()
            configUI()
        }
        
        override var preferredStatusBarStyle: UIStatusBarStyle {
            return .lightContent
        }
    
        func configUI()  {
            view.layer.contents = UIImage(named: "steve")?.cgImage
            bottomView.frame = kScreenRect
            scrollView.backgroundColor = .clear
            scrollView.delegate = self
            scrollView.contentSize = imageView.bounds.size
            scrollView.addSubview(imageView)
            view.addSubview(bottomView)
            view.addSubview(scrollView)
            
            setupZoomScale()
            scrollView.zoomScale = scrollView.minimumZoomScale
            reCenterImage()
        }
        
        func setupZoomScale() {
            let scrollViewSize = scrollView.bounds.size
            let imageSize = imageView.bounds.size
            let widthScale = scrollViewSize.width / imageSize.width
            let heightScale = scrollViewSize.height / imageSize.height
            let miniScale = min(widthScale, heightScale)
            scrollView.minimumZoomScale = miniScale
            scrollView.maximumZoomScale = 3.5
        }
        
        func reCenterImage() {
            let scrollViewSize = scrollView.bounds.size
            let imageSize = imageView.bounds.size
            let horizontalSpace = imageSize.width < scrollViewSize.width ? (scrollViewSize.width - imageSize.width)/2.0 : 0
            let verticalSpace = imageSize.height < scrollViewSize.height ? (scrollViewSize.height - imageSize.height)/2.0 : 0
            scrollView.contentInset = UIEdgeInsets(top: verticalSpace, left: horizontalSpace, bottom: verticalSpace, right: horizontalSpace)
        }
        
        
        func scrollViewDidZoom(_ scrollView: UIScrollView) {
            reCenterImage()
        }
        
        func viewForZooming(in scrollView: UIScrollView) -> UIView? {
            return imageView
        }
    }
    

    10. VideoBackground

    import Foundation
    import UIKit
    extension UIButton {
        func buttonTitle(configTitle title: String) {
            setTitle(title, for: .normal)
            titleLabel?.textColor = .white
            layer.cornerRadius = 5
            layer.borderColor = UIColor.white.cgColor
            layer.borderWidth = 1
        }
    }
    
    func configMediaPlayer() {
        let url = URL(fileURLWithPath: Bundle.main.path(forResource: "moments", ofType: "mp4")!)
        mediaPlayerVC.player = AVPlayer(url: url)
        mediaPlayerVC.videoGravity = AVLayerVideoGravityResizeAspectFill
        mediaPlayerVC.showsPlaybackControls = false
        mediaPlayerVC.view.alpha = 1
        mediaPlayerVC.view.frame = kScreenRect
        NotificationCenter.default.addObserver(self, selector: #selector(repeatPlay), name: Notification.Name.AVPlayerItemDidPlayToEndTime, object: mediaPlayerVC.player?.currentItem)
        view.addSubview(mediaPlayerVC.view)
        view.sendSubview(toBack: mediaPlayerVC.view)
        mediaPlayerVC.player?.play()
    }
    
    func repeatPlay() {
        mediaPlayerVC.player?.seek(to: kCMTimeZero)
        mediaPlayerVC.player?.play()
    }
    

    11. colorProgress

    import UIKit
    
    class GHWMainViewController: UIViewController {
        let progresss = GHWProgress(frame:CGRect(x: 20, y: 200, width: kScreenWidth - 40, height: 20))
        override func viewDidLoad() {
            super.viewDidLoad()
            configUI()
        }
        func configUI() {
            view.addSubview(progresss)
            Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { (timer) in
                self.progresss.progress = self.progresss.progress + 0.03
                if self.progresss.progress >= 1.0 {
                    timer.invalidate()
                }
            }
        }
    }
    
    import UIKit
    
    class GHWProgress: UIView, CAAnimationDelegate {
    
        let gradientLayer = CAGradientLayer()
        let maskLayer = CALayer()
        
        var progress: CGFloat = 0.0 {
            didSet {
                reConfigUI()
            }
        }
        
        override init(frame: CGRect) {
            super.init(frame: frame)
    
            configUI()
        }
        
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
        
        
        func reConfigUI() {
            maskLayer.frame = CGRect(x: 0.0, y: 0.0, width: progress * bounds.size.width, height: bounds.size.height)
        }
        
        private func configUI() {
            let whiteBG = CALayer()
            whiteBG.frame = bounds
            whiteBG.cornerRadius = bounds.size.height / 2.0
            whiteBG.borderColor = UIColor.white.cgColor
            whiteBG.borderWidth = 1.0
            layer.addSublayer(whiteBG)
            
            gradientLayer.frame = bounds
            gradientLayer.cornerRadius = bounds.size.height / 2.0
            gradientLayer.borderColor = UIColor.white.cgColor
            gradientLayer.borderWidth = 1.0
            
            var colors = [CGColor]()
            for hue in stride(from: 0, through: 360, by: 5) {
                let color = UIColor(hue: CGFloat(hue)/360.0, saturation: 1.0, brightness: 1.0, alpha: 1.0).cgColor
                colors.append(color)
            }
            gradientLayer.colors = colors
            gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
            gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
            layer.addSublayer(gradientLayer)
            
            reConfigUI()
            maskLayer.cornerRadius = bounds.size.height/2.0
            maskLayer.backgroundColor = UIColor.white.cgColor
            gradientLayer.mask = maskLayer
            
        }
        
        private func performAnimation() {
            var colors = gradientLayer.colors
            let color = colors?.popLast() as! CGColor
            colors?.insert(color, at: 0)
            
            let animation = CABasicAnimation(keyPath: "colors")
            animation.fromValue = gradientLayer.colors
            animation.toValue = colors
            animation.duration = 0.2
            animation.fillMode = kCAFillModeForwards
            animation.delegate = self
            gradientLayer.add(animation, forKey: "gradient")
            gradientLayer.colors = colors
        }
        
        func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
            performAnimation()
        }
    }
    

    12. TableHeadView

    import UIKit
    
    let YHRect = UIScreen.main.bounds
    let YHHeight = YHRect.size.height
    let YHWidth = YHRect.size.width
    
    let HeadViewHeight = YHHeight/3.0
    
    class ViewController: UIViewController {
    
        
        let datas = ["下","拉","可","以","出","现","很","神","奇","的","事","情","yo","yo","yo","yo","yo","yo"]
        let tableView = UITableView(frame: YHRect, style: .plain)
        let resueIdentifer = "CustomCell"
        let headView = UIImageView(frame: CGRect(x: 0.0, y: 0.0, width: YHWidth, height: HeadViewHeight))
        
        override func viewDidLoad() {
            super.viewDidLoad()
            setupView()
        }
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
        }
    
        
        func setupView() {
            self.automaticallyAdjustsScrollViewInsets = false
            
            headView.backgroundColor = .white
            headView.contentMode = .scaleAspectFill
            headView.clipsToBounds = true
            view.addSubview(headView)
            
            //加载图片,注意这里是URL,不是NSURL
            let url = URL(string: "http://c.hiphotos.baidu.com/zhidao/pic/item/5ab5c9ea15ce36d3c704f35538f33a87e950b156.jpg")
            let task = URLSession.shared.dataTask(with: url!) { (data, response, error) in
                guard let _ = data,error == nil else { return }
                //回到主线程
                DispatchQueue.main.sync {
                    self.headView.image = UIImage(data: data!)
                }
            }
            task.resume()
            
            tableView.delegate = self
            tableView.dataSource = self
            tableView.tableFooterView = UIView()
            tableView.register(UITableViewCell.self, forCellReuseIdentifier: resueIdentifer)
            tableView.showsVerticalScrollIndicator = false
            //下面两句必不可少,否则会出现第一次加载时位置不对的情况,这个地方一定要注意哦,非常关键
            tableView.contentInset.top = HeadViewHeight
            tableView.contentOffset = CGPoint(x: 0.0, y: -HeadViewHeight)
    //        tableView.scrollIndicatorInsets.top = HeadViewHeight//右边指示器的位置
            view.addSubview(tableView)
            view.sendSubview(toBack: tableView)
        }
    
    }
    
    extension ViewController:UITableViewDataSource, UITableViewDelegate {
        //MARK: - DataSource
        func numberOfSections(in tableView: UITableView) -> Int {
            return 1
        }
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return datas.count
        }
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: resueIdentifer, for: indexPath)
            cell.textLabel?.text = datas[indexPath.row]
            cell.textLabel?.textAlignment = .center
            return cell
        }
        
        //MARK: - Delegate
        func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
            return 50
        }
        func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
            tableView.deselectRow(at: indexPath, animated: true)
        }
        func scrollViewDidScroll(_ scrollView: UIScrollView) {
            let offsety = scrollView.contentOffset.y + scrollView.contentInset.top
            if offsety <= 0 {
                headView.frame = CGRect(x: 0.0, y: 0.0, width: YHWidth, height: HeadViewHeight-offsety)
            }else {
                let height = (HeadViewHeight-offsety) <= 0.0 ? 0.0 : (HeadViewHeight-offsety)
                headView.frame = CGRect(x: 0.0, y: 0.0, width: YHWidth, height: height)
                headView.alpha = height/HeadViewHeight
            }
        }
    }
    

    上面有涉及到tableView的,contentOffset,contentInset的使用,这里又有新的体会了。其实content包括各种header和footer,再加上cell。contentOffset就是content到frame边的距离。把握好这个就可以理解为什么开始的时候要
    tableView.contentInset.top = HeadViewHeight
    tableView.contentOffset = CGPoint(x: 0.0, y: -HeadViewHeight)
    然后tableView.addSubView的时候,是add到content上面哦。
    其实主要还是要知道哪些是content。

    13. ChildVCTransition

    import UIKit
    
    let YHRect = UIScreen.main.bounds
    let YHHeight = YHRect.size.height
    let YHWidth = YHRect.size.width
    
    let JumpNotification = "JUMP"
    
    class RootVC: UIViewController {
        
        var currentChildNumber = 0
        
        //最简单的转场实现方式,该方式是在rootVC的子VC之间转场
    
        override func viewDidLoad() {
            super.viewDidLoad()
            setupChild()
        }
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Dispose of any resources that can be recreated.
        }
        
        private func setupChild() {
            addChildViewController(ChildAVC())
            addChildViewController(ChildBVC())
            
            view.addSubview((childViewControllers.first?.view)!)
            
            //监听跳转通知,NotificationCenter通知中心
            NotificationCenter.default.addObserver(self, selector: #selector(jump), name: NSNotification.Name(rawValue: JumpNotification), object: nil)
        }
        
        func jump() {
            //options:跳转的方式
            transition(from: currentChildNumber==0 ? childViewControllers.first! : childViewControllers.last!,
                       to: currentChildNumber==0 ? childViewControllers.last! : childViewControllers.first!,
                       duration: 1,
                       options: currentChildNumber==0 ? .transitionFlipFromLeft : .transitionFlipFromRight,
                       animations: nil,
                       completion: nil)
            currentChildNumber = currentChildNumber == 0 ? 1 : 0
        }
        
        deinit {
            NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: JumpNotification), object: nil)
        }
    }
    
    import UIKit
    
    class ChildAVC: UIViewController {
        override func viewDidLoad() {
            super.viewDidLoad()
            view.backgroundColor = .green
            //添加一个点击手势
            let tap = UITapGestureRecognizer(target: self, action: #selector(jump))
            view.addGestureRecognizer(tap)
        }
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
        }
        func setupView() {
        }
        func jump() {
            //发送跳转通知
            NotificationCenter.default.post(name: NSNotification.Name(rawValue: JumpNotification), object: nil)
        }
    }
    
    

    14. MusicPlayer

    import UIKit
    import AVFoundation
    
    let YHRect = UIScreen.main.bounds
    let YHHeight = YHRect.size.height
    let YHWidth = YHRect.size.width
    
    class ViewController: UIViewController {
    
        let fileManager = FileManager.default
        let musicPath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.cachesDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).first?.appending("/music")
        var musicList = [String]()
        let tableView = UITableView(frame: YHRect)
        let resueIndetifier = "MusicCell"
        var musicPlayer: AVAudioPlayer?
        
        override func viewDidLoad() {
            super.viewDidLoad()
            saveMusicFile()
            getMusicList()
            setupView()
        }
        
        override var prefersStatusBarHidden: Bool {
            return true
        }
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Dispose of any resources that can be recreated.
        }
        
        /*沙盒文件目录:
         AppName.app:应用程序本身数据,只读。  Bundle.main.path(forResource: <#T##String?#>, ofType: <#T##String?#>)
         Documents:会被itunes备份,应用程序产生的数据,不可再生的数据放在这里
            Inbox:该目录可被外部应用程序访问,只读,需要自己创建
         Library:
            Caches:应用程序启动过程需要的信息,不会被备份,存放可再生的数据
            Preferences:偏好设置,会被itunes备份
         tmp:临时数据存放,会自动被删除
         */
        
        //保存音乐文件--这一步不是必须的,只是为了熟悉swift存储文件的操作
        func saveMusicFile() {
            let names = ["成都","童话镇"]
            //在caches创建一个music文件夹
            /*try try! try?区别:
             try:两种情况,①do {let result = try func()} catch {} 处理throw ②let result = try func() 忽略throw
             try!:相当于可选类型!,如果不throw就不会出任何问题,一旦throw,程序就会crash
             try?:把throw转换成是否是nil,而不处理具体的结果。如①if let result = try? func() {} else {} ②guard let result = try? func() else {}
             */
            print(musicPath)
            do {
                try fileManager.createDirectory(atPath: musicPath!, withIntermediateDirectories: true, attributes: nil)
                print("创建成功")
            } catch let err as NSError {
                print("创建失败:\(err.localizedFailureReason)")
                return
            }
            //把歌曲保存到caches里面
            for name in names {
                let bundlePath = Bundle.main.path(forResource: name, ofType: "m4r")
                let toPath = musicPath!.appending("/\(name).m4r")
                if fileManager.fileExists(atPath: toPath) {
                    print("已经存在\(name)")
                    continue
                }
                do {
                    try fileManager.copyItem(atPath: bundlePath!, toPath: toPath)
                    print("移动成功")
                } catch let err as NSError {
                    print("移动失败:\(err.localizedFailureReason)")
                }
            }
        }
        
        //读取音乐列表
        func getMusicList() {
            //读取、查看文件用NSFileManager
            do {
                musicList = try fileManager.contentsOfDirectory(atPath: musicPath!)
                print("查询成功:\(musicList)")
            } catch let err as NSError {
                print("查询失败:\(err.localizedFailureReason)")
            }
        }
        
        func setupView() {
            tableView.delegate = self
            tableView.dataSource = self
            tableView.tableFooterView = UIView()
            view.addSubview(tableView)
        }
        
        func playMusic(path: String) {
            if musicPlayer != nil {
                musicPlayer?.stop()
                musicPlayer = nil
            }
            do {
                try musicPlayer = AVAudioPlayer(contentsOf: URL(fileURLWithPath: path))
                //可以通过musicPlayer的属性获得歌曲的信息,包括长度,通道等信息
                print("歌曲长度:\((musicPlayer?.duration)!)")
                musicPlayer?.numberOfLoops = -1//循环次数
                musicPlayer?.delegate = self
                musicPlayer?.play()
                
            } catch let err as NSError {
                print("播放失败:\(err.localizedFailureReason)")
            }
            
        }
    
    }
    
    extension ViewController:UITableViewDataSource, UITableViewDelegate ,AVAudioPlayerDelegate {
        //MARK: - DataSource
        func numberOfSections(in tableView: UITableView) -> Int {
            return 1
        }
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return musicList.count
        }
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: resueIndetifier) ?? UITableViewCell(style: .default, reuseIdentifier: resueIndetifier)
            cell.textLabel?.text = musicList[indexPath.row]
            cell.textLabel?.textAlignment = .center
            cell.textLabel?.textColor = .orange
            cell.textLabel?.font = UIFont.systemFont(ofSize: 30, weight: 10)
            return cell
        }
        
        //MARK: - Delegate
        func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
            return 100
        }
        func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
            tableView.deselectRow(at: indexPath, animated: true)
            playMusic(path: musicPath!.appending("/\(musicList[indexPath.row])"))
        }
        
        //MARK: - AVAudioPlayerDelegate
        func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
            musicPlayer = nil
        }
    }
    
    
    

    15. ViewController转场动画

    首先一个小问题,button上面图片下面标题,extension,这个很多地方都会有需要

    import Foundation
    import UIKit
    
    extension UIButton {
        //设置按钮图片在上,文字在下的效果
        func alignContentVerticallyByCenter() {
            contentHorizontalAlignment = .center
            contentVerticalAlignment = .center
            
            //图片与title之间有一个默认的间隔10
            let offset: CGFloat = 10
            
            //在有的iOS版本上,会出现获得不到frame的情况,加上下面这两句可以100%得到
    //        titleLabel?.backgroundColor = backgroundColor
    //        imageView?.backgroundColor = backgroundColor
            
            //title
            let titleWidth = titleLabel?.frame.size.width
            let titleHeight = titleLabel?.frame.size.height
            let titleLef = titleLabel?.frame.origin.x
            let titleRig = frame.size.width-titleLef!-titleWidth!
            
            //image
            let imageWidth = imageView?.frame.size.width
            let imageHeight = imageView?.frame.size.height
            let imageLef = imageView?.frame.origin.x
            let imageRig = frame.size.width-imageLef!-imageWidth!
            
            imageEdgeInsets = UIEdgeInsets(top: 0, left: -imageLef!, bottom: titleHeight!, right: -imageRig)
            titleEdgeInsets = UIEdgeInsets(top: imageHeight!+offset, left: -titleLef!, bottom: 0, right: -titleRig)
        }
    }
    
    

    然后就是UIViewControllerAnimatedTransitioning和UIViewControllerTransitioningDelegate

    UIViewControllerAnimatedTransitioning:这个接口负责切换的具体内容,也即“切换中应该发生什么”。开发者在做自定义切换效果时大部分代码会是用来实现这个接口。它只有两个方法需要我们实现。
    UIViewControllerTransitioningDelegate:这个接口的作用比较简单单一,在需要VC切换的时候系统会像实现了这个接口的对象询问是否需要使用自定义的切换效果。这个接口共有四个类似的方法。

    具体实现代码看下面:

    import UIKit
    
    class MenuTransitionManger: NSObject, UIViewControllerAnimatedTransitioning, UIViewControllerTransitioningDelegate {
    
        
        private var presenting = false
    
        
        func offStage(amount: CGFloat) -> CGAffineTransform {
            //返回平移x,y的结构体
            return CGAffineTransform(translationX: amount, y: 0)
        }
        
        //关
    
        func offStageMenuController(menuVC: MenuViewController) {
            menuVC.view.alpha = 0
            
            let topRowOffset: CGFloat = 300
            let middleRowOffset: CGFloat = 150
            let bottomRowOffset: CGFloat = 50
            
            menuVC.btns[0].transform = offStage(amount: -topRowOffset)
            menuVC.btns[1].transform = offStage(amount: topRowOffset)
            menuVC.btns[2].transform = offStage(amount: -middleRowOffset)
            menuVC.btns[3].transform = offStage(amount: middleRowOffset)
            menuVC.btns[4].transform = offStage(amount: -bottomRowOffset)
            menuVC.btns[5].transform = offStage(amount: bottomRowOffset)
        }
        
        //开
        func onStageMenuController(menuVC: MenuViewController) {
            menuVC.view.alpha = 1
            
            menuVC.btns[0].transform = CGAffineTransform.identity
            menuVC.btns[1].transform = CGAffineTransform.identity
            menuVC.btns[2].transform = CGAffineTransform.identity
            menuVC.btns[3].transform = CGAffineTransform.identity
            menuVC.btns[4].transform = CGAffineTransform.identity
            menuVC.btns[5].transform = CGAffineTransform.identity
        }
        
        //MARK: - UIViewControllerAnimatedTransitioning
        func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
            let container = transitionContext.containerView
            let screens: (from: UIViewController, to: UIViewController) = (transitionContext.viewController(forKey: .from)!, transitionContext.viewController(forKey: .to)!)
            let menuVC = !presenting ? screens.from as! MenuViewController : screens.to as! MenuViewController
            let bottomVC = !presenting ? screens.to : screens.from
            let menuV = menuVC.view
            let bottomV = bottomVC.view
            
            if self.presenting {
                offStageMenuController(menuVC: menuVC)
            }
            
            container.addSubview(bottomV!)
            container.addSubview(menuV!)
            
            let duration = self.transitionDuration(using: transitionContext)
            
            UIView.animate(withDuration: duration,
                           delay: 0.0,
                           usingSpringWithDamping: 0.7,
                           initialSpringVelocity: 0.8,
                           options: [],
                           animations: { 
                            self.presenting ? self.onStageMenuController(menuVC: menuVC) : self.offStageMenuController(menuVC: menuVC)
                },
                           completion: { finished in
                            transitionContext.completeTransition(true)
                            if self.presenting {
                                UIApplication.shared.keyWindow?.addSubview(screens.from.view)
                            }
                            UIApplication.shared.keyWindow?.addSubview(screens.to.view)
                }
            )
        }
        
        func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
            return 0.5
        }
        
        
        //MARK: - UIViewControllerTransitioningDelegate
        
        func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            self.presenting = true
            return self
        }
        
        func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            self.presenting = false
            return self
        }
    
    }
    

    16. 多级列表


    这个demo里面重点关注

    1. 数据结构struct City Province
    2. initDatas()中对数据的处理
    3. viewForHeaderInSection中对手势的添加
    4. 采用runtime为手势增加一个tag属性,标记手势。
    
    import UIKit
    
    
    struct City {
        
        let name: String
        let alias: String
    }
    
    
    struct Province {
        
        let name: String
        var citys: [City]
        var isOpen: Bool
    }
    
    
    class ViewController: UIViewController {
        
        
        let tableView = UITableView(frame: YHRect, style: .plain)
        let reuseIdentifer = "Cell"
        let reuseHeaderIdentifer = "HeaderCell"
        var datas = [Province]()
        
    
        override func viewDidLoad() {
            super.viewDidLoad()
            initDatas()
            setupView()
        }
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
        }
        
        
        func initDatas() {
            
            let dic = NSDictionary(contentsOfFile: Bundle.main.path(forResource: "Province", ofType: "plist")!)
            dic?.enumerateKeysAndObjects({ (key, value, roolback) in
                let values = value as! NSDictionary
                var citys = [City]()
                for k in values.allKeys {
                    let city = City(name: k as! String, alias: values[k] as! String)
                    citys.append(city)
                }
                let pro = Province(name: key as! String, citys: citys, isOpen: false)
                datas.append(pro)
            })
        }
        
        
        func setupView() {
            
            tableView.delegate = self
            tableView.dataSource = self
            tableView.tableFooterView = UIView()
            tableView.register(CustomHeaderView.self, forHeaderFooterViewReuseIdentifier: reuseHeaderIdentifer)
            view.addSubview(tableView)
        }
    }
    
    
    extension ViewController:UITableViewDataSource, UITableViewDelegate {
        
        //MARK: - DataSource
        func numberOfSections(in tableView: UITableView) -> Int {
            return datas.count
        }
        
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            let province = datas[section]
            return province.isOpen ? province.citys.count : 0
        }
        
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: reuseIdentifer) ?? UITableViewCell(style: .value1, reuseIdentifier: reuseIdentifer)
            let city = datas[indexPath.section].citys[indexPath.row]
            cell.textLabel?.text = city.name
            cell.textLabel?.textColor = .orange
            cell.textLabel?.textAlignment = .center
            cell.detailTextLabel?.text = city.alias
            cell.detailTextLabel?.font = UIFont.systemFont(ofSize: 12)
            return cell
        }
        
        func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
            let view = tableView.dequeueReusableHeaderFooterView(withIdentifier: reuseHeaderIdentifer) as! CustomHeaderView
            
            func addTap() {
                let tap = UITapGestureRecognizer(target: self, action: #selector(headerTap(sender:)))
                tap.tag = section
                view.addGestureRecognizer(tap)
            }
            
            print("手势数目:\(view.gestureRecognizers?.count)")
            if let grs = view.gestureRecognizers {
                grs.count > 0 ? (grs.first as! UITapGestureRecognizer).tag = section : addTap()
            }else {
                addTap()
            }
            view.buildUI(province: datas[section])
            return view
        }
        
        //MARK: - GR
        func headerTap(sender: UITapGestureRecognizer) {
            
            datas[sender.tag].isOpen = !datas[sender.tag].isOpen
            tableView.reloadSections([sender.tag], with: .fade)
        }
        
        //MARK: - Delegate
        func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
            return 50
        }
        
        func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
            return 70
        }
        
        func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
            tableView.deselectRow(at: indexPath, animated: true)
        }
        
    }
    var AssociatedObjectHandle: UInt8 = 0
    
    //采用runtime为手势增加一个tag属性,标记手势。
    extension UITapGestureRecognizer {
        
    //    struct AddProperty {
    //        static var tag: Int = 0
    //    }
    //    
        var tag: Int {
            get {
                return objc_getAssociatedObject(self, &AssociatedObjectHandle) as! Int
            }
            set {
                objc_setAssociatedObject(self, &AssociatedObjectHandle, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
            }
        }
    }
    
    

    相关文章

      网友评论

          本文标题:Swift小demo学习笔记

          本文链接:https://www.haomeiwen.com/subject/ndjnkxtx.html