2016-07-17 23 views
6

iOS 10有一個我想要複製的功能。當您在Apple Music應用程序中觸摸相冊時,會打開下面顯示的菜單。然而,與正常的偷看和流行不同,當你舉起手指時,它不會消失。我如何複製這個?如何複製iOS 10的Apple音樂「Peek and pop action menu」

enter image description here

+0

你確定這是一個3D觸摸,而不只是一個長按?它也適用於我的iPhone 6+,它沒有3D Touch。 – Fogmeister

+0

@Fogmeister好吧,我去了,關閉3D觸摸。如果您注意到它顯示了相同的內容,但在底部添加了取消按鈕。我真的想要做到這一點。但我怎麼做的問題依然存在。 –

+0

而不是使用偷看和流行的塞格式是不可能使用某種形式的力量觸摸手勢來觸發它?我目前不在電腦上,但這正是我期待的。 – Fogmeister

回答

1

我得複製它下面的代碼。它創建音樂應用程序的虛擬複製品最接近的。然後我加入PeekPop-3D觸控代表。

但是,在委託中,我添加了一個觀察者到手勢識別器,然後在偷看時取消手勢,但是當手指擡起時重新啓用手勢。爲了重新啓用它,我做了異步操作,因爲預覽將立即消失,而不需要異步調度。我找不到辦法解決它..

現在,如果你點擊藍色的窗口外面,它就會消失像正常=]

http://i.imgur.com/073M2Ku.jpg http://i.imgur.com/XkwUBly.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) 
    } 
} 
+0

我猜我失去的是我不必向上滑動。我知道當我觸摸一個文本線程並向上滑動時,我會得到回覆選項。但是當我用3D觸摸一張專輯時,它只是爲上面顯示的屏幕製作動畫。沒有刷過或什麼。 –

0

實際上可以使用UIPreviewInteraction API來完成。

https://developer.apple.com/documentation/uikit/uipreviewinteraction

這幾乎是類似皮克和流行API

這裏我們有兩個階段:Preview和Commit,它們對應於後面的API中的Peek和Pop。我們有UIPreviewInteractionDelegate,它使我們能夠訪問通過這些階段的過渡。

一個應該做的那麼什麼是,複製上面的蘋果音樂彈出,

其實,蘋果已經以聊天應用程序的形式構建了這個演示。

here下載示例代碼並進行測試。