2016-07-17 3 views
6

В iOS 10 есть функция, которую я хотел бы воспроизвести. Когда вы 3D касаетесь альбома в приложении Apple Music, он открывает меню, показанное ниже. Однако, в отличие от обычного взгляда и поп-музыки, он не исчезает, когда вы поднимаете палец. Как это сделать?Как копировать iOS 10 в Apple Music «Меню Peek and pop action»

enter image description here

+0

Вы уверены, что это 3D Touch, а не только длинная печать? Он также работает на моем iPhone 6+, у которого нет 3D Touch. – Fogmeister

+0

@Fogmeister Итак, я пошел и отключил 3D-касание. Если вы заметите, что он показывает те же самые вещи, но внизу, добавлена ​​кнопка отмены. Я бы действительно хотел сделать то и другое. Но вопрос о том, как я это сделаю, все же стоит. –

+0

вместо того, чтобы использовать peek и pop segue, нельзя ли использовать какой-то жест касания силы, чтобы вызвать его? На данный момент я не на своем компьютере, но это то, что я бы искал. – Fogmeister

ответ

1

Ближайшим я получил тиражирование это следующий код .. Это создает фиктивную копию приложения Music .. Затем я добавил делегат PeekPop-3D-Touch.

Однако в делегате я добавляю наблюдателя к распознавателю жестов, а затем отменяю жест при подглядывании, но затем снова включаю его, когда палец поднимается. Чтобы снова включить его, я сделал это async, потому что предварительный просмотр сразу исчезнет без отправки async. Я не мог найти путь вокруг него ..

Теперь, если вы нажмете за пределами синей коробке, она исчезнет, ​​как нормальный =]

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 касаюсь текстового потока и проведите пальцем вверх, я получаю ответы. Но когда я 3D касаюсь альбома, он просто оживляет экран, показанный выше. Никаких размахов или чего-либо еще. –

0

Это действительно может быть сделано с использованием UIPreviewInteraction API.

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

Это почти похоже на Peek и Pop API.

Здесь у нас есть 2 этапа: Предварительный просмотр и Commit, которые соответствуют Peek и Pop в более позднем API. мы имеем UIPreviewInteractionDelegate, что дает нам доступ к переходу через эти фазы.

Так что нужно сделать, это, чтобы скопировать выше Apple Music Всплывающие,

  • вручную показать размытия накладку во время didUpdatePreviewTransition

  • Построить XIB из меню выше и показать его во время didUpdateCommitTransition

  • Вы можете сделать так, чтобы вид оставался там на завершающем этапе commitTransition.

На самом деле, яблоко построено демо этого в виде приложения чата.

Загрузите образец кода от here и проверьте его.

Смежные вопросы