如何复制 iOS 10 的 Apple Music“查看和弹出操作菜单”

2023-11-26

iOS 10 有一个我想复制的功能。当您在 Apple Music 应用中 3D 触摸专辑时,它会打开如下所示的菜单。然而,与普通的窥视和弹出不同,当您抬起手指时,它不会消失。我该如何复制这个?

enter image description here


我最接近复制它的是以下代码。它创建了音乐应用程序的虚拟副本。然后我添加了 PeekPop-3D-Touch 代表。

但是,在委托中,我向手势识别器添加了一个观察者,然后在查看时取消手势,但在抬起手指时重新启用它。为了重新启用它,我进行了异步操作,因为如果没有异步调度,预览将立即消失。我找不到解决办法..

现在,如果你点击蓝色框外,它就会像平常一样消失=]

https://i.stack.imgur.com/68Rwd.jpg https://i.stack.imgur.com/sOTnP.jpg

enter image description here enter image description here

//
//  ViewController.swift
//  PeekPopExample
//
//  Created by Brandon Anthony on 2016-07-16.
//  Copyright © 2016 XIO. All rights reserved.
//

import UIKit


class MusicViewController: UITabBarController, UITabBarControllerDelegate {

    var tableView: UITableView!
    var collectionView: UICollectionView!

    override func viewDidLoad() {
        super.viewDidLoad()

        self.initControllers()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    func initControllers() {
        let libraryController = LibraryViewController()
        let forYouController = UIViewController()
        let browseController = UIViewController()
        let radioController = UIViewController()
        let searchController = UIViewController()

        libraryController.title = "Library"
        libraryController.tabBarItem.image = nil

        forYouController.title = "For You"
        forYouController.tabBarItem.image = nil

        browseController.title = "Browse"
        browseController.tabBarItem.image = nil

        radioController.title = "Radio"
        radioController.tabBarItem.image = nil

        searchController.title = "Search"
        searchController.tabBarItem.image = nil

        self.viewControllers = [libraryController, forYouController, browseController, radioController, searchController];
    }


}

并且 ForceTouch 的执行暂停..

//
//  LibraryViewController.swift
//  PeekPopExample
//
//  Created by Brandon Anthony on 2016-07-16.
//  Copyright © 2016 XIO. All rights reserved.
//

import Foundation
import UIKit


//Views and Cells..

class AlbumView : UIView {
    var albumCover: UIImageView!
    var title: UILabel!
    var artist: UILabel!

    override init(frame: CGRect) {
        super.init(frame: frame)

        self.initControls()
        self.setTheme()
        self.doLayout()
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func initControls() {
        self.albumCover = UIImageView()
        self.title = UILabel()
        self.artist = UILabel()
    }

    func setTheme() {
        self.albumCover.contentMode = .scaleAspectFit
        self.albumCover.layer.cornerRadius = 5.0
        self.albumCover.backgroundColor = UIColor.lightGray()

        self.title.text = "Unknown"
        self.title.font = UIFont.systemFont(ofSize: 12)

        self.artist.text = "Unknown"
        self.artist.textColor = UIColor.lightGray()
        self.artist.font = UIFont.systemFont(ofSize: 12)
    }

    func doLayout() {
        self.addSubview(self.albumCover)
        self.addSubview(self.title)
        self.addSubview(self.artist)

        let views = ["albumCover": self.albumCover, "title": self.title, "artist": self.artist];
        var constraints = Array<String>()

        constraints.append("H:|-0-[albumCover]-0-|")
        constraints.append("H:|-0-[title]-0-|")
        constraints.append("H:|-0-[artist]-0-|")
        constraints.append("V:|-0-[albumCover]-[title]-[artist]-0-|")

        let aspectRatioConstraint = NSLayoutConstraint(item: self.albumCover, attribute: .width, relatedBy: .equal, toItem: self.albumCover, attribute: .height, multiplier: 1.0, constant: 0.0)

        self.addConstraint(aspectRatioConstraint)

        for constraint in constraints {
            self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: constraint, options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views))
        }

        for view in self.subviews {
            view.translatesAutoresizingMaskIntoConstraints = false
        }
    }
}

class AlbumCell : UITableViewCell {
    var firstAlbumView: AlbumView!
    var secondAlbumView: AlbumView!

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)

        self.initControls()
        self.setTheme()
        self.doLayout()
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func initControls() {
        self.firstAlbumView = AlbumView(frame: CGRect.zero)
        self.secondAlbumView = AlbumView(frame: CGRect.zero)
    }

    func setTheme() {

    }

    func doLayout() {
        self.contentView.addSubview(self.firstAlbumView)
        self.contentView.addSubview(self.secondAlbumView)

        let views: [String: AnyObject] = ["firstAlbumView": self.firstAlbumView, "secondAlbumView": self.secondAlbumView];
        var constraints = Array<String>()

        constraints.append("H:|-15-[firstAlbumView(==secondAlbumView)]-15-[secondAlbumView(==firstAlbumView)]-15-|")
        constraints.append("V:|-15-[firstAlbumView]-15-|")
        constraints.append("V:|-15-[secondAlbumView]-15-|")

        for constraint in constraints {
            self.contentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: constraint, options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views))
        }

        for view in self.contentView.subviews {
            view.translatesAutoresizingMaskIntoConstraints = false
        }
    }
}



//Details..

class DetailSongViewController : UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        self.view.backgroundColor = UIColor.blue()
    }

    /*override func previewActionItems() -> [UIPreviewActionItem] {
        let regularAction = UIPreviewAction(title: "Regular", style: .default) { (action: UIPreviewAction, vc: UIViewController) -> Void in

        }

        let destructiveAction = UIPreviewAction(title: "Destructive", style: .destructive) { (action: UIPreviewAction, vc: UIViewController) -> Void in

        }

        let actionGroup = UIPreviewActionGroup(title: "Group...", style: .default, actions: [regularAction, destructiveAction])

        return [actionGroup]
    }*/
}











//Implementation..

extension LibraryViewController : UIViewControllerPreviewingDelegate {
    func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {

        guard let indexPath = self.tableView.indexPathForRow(at: location) else {
            return nil
        }

        guard let cell = self.tableView.cellForRow(at: indexPath) else {
            return nil
        }


        previewingContext.previewingGestureRecognizerForFailureRelationship.addObserver(self, forKeyPath: "state", options: .new, context: nil)


        let detailViewController = DetailSongViewController()
        detailViewController.preferredContentSize = CGSize(width: 0.0, height: 300.0)
        previewingContext.sourceRect = cell.frame
        return detailViewController
    }

    func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {

        //self.show(viewControllerToCommit, sender: self)
    }

    override func observeValue(forKeyPath keyPath: String?, of object: AnyObject?, change: [NSKeyValueChangeKey : AnyObject]?, context: UnsafeMutablePointer<Void>?) {
        if let object = object {
            if keyPath == "state" {
                let newValue = change![NSKeyValueChangeKey.newKey]!.integerValue
                let state = UIGestureRecognizerState(rawValue: newValue!)!
                switch state {
                case .began, .changed:
                    self.navigationItem.title = "Peeking"
                    (object as! UIGestureRecognizer).isEnabled = false

                case .ended, .failed, .cancelled:
                    self.navigationItem.title = "Not committed"
                    object.removeObserver(self, forKeyPath: "state")

                    DispatchQueue.main.async(execute: { 
                        (object as! UIGestureRecognizer).isEnabled = true
                    })


                case .possible:
                    break
                }
            }
        }
    }
}


class LibraryViewController : UIViewController, UITableViewDelegate, UITableViewDataSource {

    var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()

        self.initControls()
        self.setTheme()
        self.registerClasses()
        self.registerPeekPopPreviews();
        self.doLayout()
    }

    func initControls() {
        self.tableView = UITableView(frame: CGRect.zero, style: .grouped)
    }

    func setTheme() {
        self.edgesForExtendedLayout = UIRectEdge()
        self.tableView.dataSource = self;
        self.tableView.delegate = self;
    }

    func registerClasses() {
        self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Default")
        self.tableView.register(AlbumCell.self, forCellReuseIdentifier: "AlbumCell")
    }

    func registerPeekPopPreviews() {
        //if (self.traitCollection.forceTouchCapability == .available) {
            self.registerForPreviewing(with: self, sourceView: self.tableView)
        //}
    }

    func doLayout() {
        self.view.addSubview(self.tableView)

        let views: [String: AnyObject] = ["tableView": self.tableView];
        var constraints = Array<String>()

        constraints.append("H:|-0-[tableView]-0-|")
        constraints.append("V:|-0-[tableView]-0-|")

        for constraint in constraints {
            self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: constraint, options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views))
        }

        for view in self.view.subviews {
            view.translatesAutoresizingMaskIntoConstraints = false
        }
    }



    func numberOfSections(in tableView: UITableView) -> Int {
        return 2
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return section == 0 ? 5 : 10
    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return (indexPath as NSIndexPath).section == 0 ? 44.0 : 235.0
    }

    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return section == 0 ? 75.0 : 50.0
    }

    func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
        return 0.0001
    }

    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return section == 0 ? "Library" : "Recently Added"
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        if (indexPath as NSIndexPath).section == 0 { //Library
            let cell = tableView.dequeueReusableCell(withIdentifier: "Default", for: indexPath)

            switch (indexPath as NSIndexPath).row {
            case 0:
                cell.accessoryType = .disclosureIndicator
                cell.textLabel?.text = "Playlists"

            case 1:
                cell.accessoryType = .disclosureIndicator
                cell.textLabel?.text = "Artists"

            case 2:
                cell.accessoryType = .disclosureIndicator
                cell.textLabel?.text = "Albums"

            case 3:
                cell.accessoryType = .disclosureIndicator
                cell.textLabel?.text = "Songs"

            case 4:
                cell.accessoryType = .disclosureIndicator
                cell.textLabel?.text = "Downloads"


            default:
                break
            }
        }

        if (indexPath as NSIndexPath).section == 1 {  //Recently Added
            let cell = tableView.dequeueReusableCell(withIdentifier: "AlbumCell", for: indexPath)
            cell.selectionStyle = .none
            return cell
        }

        return tableView.dequeueReusableCell(withIdentifier: "Default", for: indexPath)
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何复制 iOS 10 的 Apple Music“查看和弹出操作菜单” 的相关文章

随机推荐

  • Apache Solr java 教程 [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心以获得指导 我是 Apache sol
  • POST/PUT Json RESTful 请求 Grails 的问题

    嗨 我有一个 grails 宁静的代码 我完善了一个 Json 获取和删除请求 我的问题是 我想使用 json 执行 Put 或 post 请求 但如果我使用程序来执行此操作 它会出现错误 我无法执行此操作 这是我的代码 一类 packag
  • jquery masonry 在初始页面加载时崩溃,单击“主页”菜单按钮后工作正常

    我的 jquery masonry 设置在初始页面加载时工作得很奇怪 似乎将图像放置在第一行中 第二行的位置与第一行重叠 第三行的位置相同 页面加载后 您可以单击主页按钮或徽标并重新加载页面 它可以正常工作 我在functions php中
  • ASP.NET XML 解析错误:找不到元素行号 1,列 1 错误

    嘿 我发现了一个奇怪的喜怒无常的页面 它随机地给我以下错误 XML Parsing Error no element found Location http kj2011 site 2011 nonprofit database overv
  • Linq To Sql 和全文搜索 - 可以做到吗?

    有没有人想出一种执行全文搜索的好方法 FREETEXT CONTAINS 对于使用标准 LinqToSql 查询语法的任意数量的任意关键字 我显然希望避免必须使用存储过程或必须生成动态 SQL 调用 显然 我可以将搜索字符串输入到使用 FR
  • 如何在某些元素上禁用 Cufon?

    我目前在您的网站上使用 Cufon 其类似于Cufon set fontFamily DIN Medium replace h1 现在 对于单个 H1 标签 我希望禁用 Cufon 这不会将 H1 标签更改为任何其他标签 它必须保持原样 如
  • Delphi非对称加密

    我正在寻找非对称加密算法的 Delphi 实现 而不依赖于外部 DLL 有可用的吗 我的目标是使用公钥 私钥对加密 解密字符串 或字节数组 安全黑盒Eldos 提供原生 全面的解决方案 包括证书管理和对外部加密设备 即 USB 令牌 的访问
  • 在 Android 中以管理员身份禁用应用程序之前需要密码

    我正在开发一个作为Admin 我可以使用以下代码来做到这一点 演示 DeviceAdminReceiver jav public class DemoDeviceAdminReceiver extends DeviceAdminReceiv
  • 使用 Bouncy Castle 签署 CSR

    我找不到任何描述如何使用 BC 签署 CSR 的代码 文档 作为输入 我有一个 CSR 作为字节数组 并且希望获得 PEM 和 或 DER 格式的证书 我已经走到这一步了 def signCSR csrData Array Byte ca
  • View 被推出 ConstraintLayout 中的约束

    我有一个约束布局与图像视图和 3 个链式文本视图 with a spread inside链条款式
  • R:将“特殊”字母转换为UTF-8?

    我在匹配表时遇到问题 其中一个数据帧包含特殊字符 而另一个数据帧不包含特殊字符 示例 做 安娜县 vs 多纳安娜县 这是一个可以重现输出的脚本 library tidyverse library acs tbl df acs fips pl
  • C++11 初始值设定项列表失败 - 但仅限于长度为 2 的列表

    我发现了一个不起眼的日志记录错误 因为长度为 2 的初始值设定项列表似乎是一个特殊情况 这怎么可能 该代码是使用 Apple LLVM 版本 5 1 clang 503 0 40 编译的 使用CXXFLAGS std c 11 stdlib
  • 如何在 SQLAlchemy 中使用 joinload/contains_eager 来实现启用查询的关系(lazy='dynamic' 选项)

    我有 SQLAlchemy 声明的以下模型类 class User Base id Column Integer primary key True name Column String nullable False unique True
  • 在 Matplotlib 中以科学记数法显示第一个小数位

    我目前正在使用 y 轴的科学记数法生成不同的数字 导致某些图上的刻度为 2 或 6 而另一些图上的刻度为 2 5 或 8 9 我希望 y 轴上始终保留一位小数的刻度 即使它添加了零 这是一个例子 import matplotlib pypl
  • 了解 Python 配置文件输出

    我正在尝试使用 Python 分析器来加速我的代码 我已经能够确定几乎所有时间都花在哪个特定函数上 但我无法弄清楚该函数中的时间花在哪里 下面是配置文件输出 其中显示 appendBallot 是罪魁祸首 耗时近 116 秒 下面 我有 a
  • 如何在Linux内核设备驱动程序中使用定时器?

    我想在 Linux 设备驱动程序中实现一个计数器 该计数器在每个固定时间间隔后递增 我想在计时器的帮助下做到这一点 示例代码片段将非常有用 看看下面的文章IBM Developerworks 计时器和列表 有一个如何使用 Linux 内核定
  • Swift 中忽略参数的用途是什么

    在 Swift 中 您可以编写以下内容 func foo Int gt return 1 其中下划线是被忽略的参数 我只是因为文档才知道这一点 但想不出任何关于为什么你会这样做的用例 我错过了什么吗 在以下情况下 忽略参数 或元组的成员 它
  • HtmlAgilityPack ——
    是否会因某种原因自行关闭?

    我只是写了这个测试来看看我是否疯了 using System using System Collections Generic using System Linq using System Text using HtmlAgilityPac
  • 是否有一种颜色混合算法可以像混合真实颜色一样工作?

    常见的 RGB 颜色混合与绘画颜色的混合有很大不同 它是光的混合而不是颜料的混合 例如 Blue 0 0 255 Yellow 255 255 0 Grey 128 128 128 应该是蓝色 黄色 绿色 是否有任何已知的颜色混合算法可以像
  • 如何复制 iOS 10 的 Apple Music“查看和弹出操作菜单”

    iOS 10 有一个我想复制的功能 当您在 Apple Music 应用中 3D 触摸专辑时 它会打开如下所示的菜单 然而 与普通的窥视和弹出不同 当您抬起手指时 它不会消失 我该如何复制这个 我最接近复制它的是以下代码 它创建了音乐应用程