2016-07-17 112 views
6

iOS 10 ha una funzione che vorrei replicare. Quando tocchi un album 3D nell'app Apple Music, si apre il menu mostrato di seguito. Tuttavia a differenza di una normale sbirciatina e pop, non va via quando alzi il dito. Come posso replicare questo?Come faccio a replicare Apple Music di iOS 10 "Menu di azione Peek e pop"

enter image description here

+0

Sei sicuro che sia un 3D Touch e non solo una lunga pressione? Funziona anche con il mio iPhone 6+ che non ha 3D Touch. – Fogmeister

+0

@Fogmeister Ok, quindi sono andato e ho disattivato il tocco 3D. Se noti che mostra le stesse cose ma in fondo con un pulsante Annulla aggiunto. Mi piacerebbe davvero fare entrambe le cose. Ma il problema di come lo farei è ancora valido. –

+0

piuttosto che usare un peek e un pop segue non è possibile usare una sorta di gesto di tocco di forza per attivarlo? Al momento non sono sul mio computer, ma è quello che cerco. – Fogmeister

risposta

1

Il più vicino ho avuto modo di replicare è il seguente codice .. E creare un manichino-replica dell'applicazione Musica .. poi ho aggiunto i delegati PeekPop-3D-Touch.

Tuttavia, nel delegato, aggiungo un osservatore al rilevatore di gesti e quindi annullo il gesto dopo averlo sbirciato ma poi lo riatroo quando il dito è sollevato. Per riattivarlo, l'ho fatto asincrono perché l'anteprima sparirà immediatamente senza la distribuzione asincrona. Non riuscivo a trovare un modo intorno ad esso ..

Ora, se si tocca fuori della scatola blu, sparirà come normale =]

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]; 
    } 


} 

E l'implementazione di ForceTouch in pausa ..

// 
// 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

Credo che dove mi sono perso è che non devo scorrere verso l'alto. So che quando tocco 3D un thread di testo e scorro verso l'alto ottengo le opzioni di risposta. Ma quando tocco 3D un album, si anima solo lo schermo mostrato sopra. Niente swiping o niente –

0

Questa operazione potrebbe essere eseguita utilizzando UIPreviewInteraction API.

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

è quasi simile al Peek e Pop API.

Qui abbiamo 2 fasi: Anteprima e Conferma che corrispondono a Peek e Pop nell'API successiva. abbiamo UIPreviewInteractionDelegate che ci dà l'accesso alla transizione attraverso queste fasi.

Allora, cosa si dovrebbe fare è, per replicare quanto sopra Apple Music Popup,

In realtà, Apple ha creato una demo di questo sotto forma di app di chat.

Scaricare il codice di esempio da here e provarlo.

Problemi correlati