Bagaimana cara meniru lembar bawah dari aplikasi Maps?


202

Adakah yang bisa memberi tahu saya cara meniru lembar terbawah di aplikasi Maps baru di iOS 10?

Di Android, Anda dapat menggunakan BottomSheetyang meniru perilaku ini, tetapi saya tidak dapat menemukan hal seperti itu untuk iOS.

Apakah itu tampilan gulir sederhana dengan sisipan konten, sehingga bilah pencarian di bagian bawah?

Saya cukup baru untuk pemrograman iOS sehingga jika seseorang dapat membantu saya membuat tata letak ini, itu akan sangat dihargai.

Inilah yang saya maksud dengan "lembaran bawah":

tangkapan layar lembar bawah yang diciutkan di Maps

tangkapan layar lembar bawah yang diperluas di Maps


1
Anda harus membangunnya sendiri, saya khawatir. Ini adalah tampilan dengan latar belakang buram dan beberapa pengenal isyarat.
Khanh Nguyen

@KhanhNguyen ya saya tahu saya harus membangunnya sendiri, tapi yang saya ingin tahu adalah pandangan mana yang digunakan untuk mengarsipkan efek ini dan bagaimana mereka dipesan dan sebagainya
qwertz

Tampilan efek visual dengan efek blur. Lihat pertanyaan SO
Khanh Nguyen

1
Saya pikir Anda dapat menambahkan recogniser gerakan pan ke tampilan bawah dan memindahkan tampilan sesuai (dengan mengamati perubahan dengan menyimpan koordinat y antara peristiwa recogniser gerakan, dan menghitung perbedaannya).
Khanh Nguyen

2
Saya suka pertanyaan Anda. Saya berencana untuk mengimplementasikan sesuatu seperti ini. Jika seseorang bisa menulis beberapa contoh akan menyenangkan.
wviana

Jawaban:


330

Saya tidak tahu bagaimana tepatnya lembar terbawah aplikasi Maps yang baru, merespons interaksi pengguna. Tetapi Anda dapat membuat tampilan kustom yang terlihat seperti yang ada di tangkapan layar dan menambahkannya ke tampilan utama.

Saya berasumsi Anda tahu cara:

1- membuat pengendali tampilan baik oleh storyboard atau menggunakan file xib.

2- menggunakan googleMaps atau MapKit Apple.

Contoh

1- Buat 2 pengendali tampilan, misalnya, MapViewController dan BottomSheetViewController . Kontroler pertama akan menjadi tuan rumah peta dan yang kedua adalah lembar bawah itu sendiri.

Konfigurasikan MapViewController

Buat metode untuk menambahkan tampilan lembar bawah.

func addBottomSheetView() {
    // 1- Init bottomSheetVC
    let bottomSheetVC = BottomSheetViewController()

    // 2- Add bottomSheetVC as a child view 
    self.addChildViewController(bottomSheetVC)
    self.view.addSubview(bottomSheetVC.view)
    bottomSheetVC.didMoveToParentViewController(self)

    // 3- Adjust bottomSheet frame and initial position.
    let height = view.frame.height
    let width  = view.frame.width
    bottomSheetVC.view.frame = CGRectMake(0, self.view.frame.maxY, width, height)
}

Dan menyebutnya dengan metode viewDidAppear:

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)
    addBottomSheetView()
}

Konfigurasikan BottomSheetViewController

1) Mempersiapkan latar belakang

Buat metode untuk menambahkan efek blur dan semangat

func prepareBackgroundView(){
    let blurEffect = UIBlurEffect.init(style: .Dark)
    let visualEffect = UIVisualEffectView.init(effect: blurEffect)
    let bluredView = UIVisualEffectView.init(effect: blurEffect)
    bluredView.contentView.addSubview(visualEffect)

    visualEffect.frame = UIScreen.mainScreen().bounds
    bluredView.frame = UIScreen.mainScreen().bounds

    view.insertSubview(bluredView, atIndex: 0)
}

panggil metode ini di viewWillAppear Anda

override func viewWillAppear(animated: Bool) {
   super.viewWillAppear(animated)
   prepareBackgroundView()
}

Pastikan warna latar belakang tampilan pengontrol Anda clearColor.

2) menghidupkan tampilan bawah lembar

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)

    UIView.animateWithDuration(0.3) { [weak self] in
        let frame = self?.view.frame
        let yComponent = UIScreen.mainScreen().bounds.height - 200
        self?.view.frame = CGRectMake(0, yComponent, frame!.width, frame!.height)
    }
}

3) Ubah xib Anda seperti yang Anda inginkan.

4) Tambahkan Pan Gesture Recognizer ke tampilan Anda.

Dalam metode viewDidLoad Anda, tambahkan UIPanGestureRecognizer.

override func viewDidLoad() {
    super.viewDidLoad()

    let gesture = UIPanGestureRecognizer.init(target: self, action: #selector(BottomSheetViewController.panGesture))
    view.addGestureRecognizer(gesture)

}

Dan terapkan perilaku gerakan Anda:

func panGesture(recognizer: UIPanGestureRecognizer) {
    let translation = recognizer.translationInView(self.view)
    let y = self.view.frame.minY
    self.view.frame = CGRectMake(0, y + translation.y, view.frame.width, view.frame.height)
     recognizer.setTranslation(CGPointZero, inView: self.view)
}

Lembar Bawah yang Dapat Digulir:

Jika tampilan khusus Anda adalah tampilan gulir atau tampilan lain yang mewarisi, maka Anda memiliki dua opsi:

Pertama:

Rancang tampilan dengan tampilan header dan tambahkan panGesture ke header. (pengalaman pengguna yang buruk) .

Kedua:

1 - Tambahkan panGesture ke tampilan lembar bawah.

2 - Menerapkan delegasi UIGestureRecognizerDelegate dan mengatur delegasi panGesture ke controller.

3- Implementasikan shouldRecognizeSimurrentouslyDengan fungsi delegasi dan nonaktifkan properti scrollView isScrollEnabled dalam dua kasus:

  • Tampilan sebagian terlihat.
  • Tampilan benar-benar terlihat, properti scrollView contentOffset adalah 0 dan pengguna menyeret tampilan ke bawah.

Jika tidak, aktifkan pengguliran.

  func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
      let gesture = (gestureRecognizer as! UIPanGestureRecognizer)
      let direction = gesture.velocity(in: view).y

      let y = view.frame.minY
      if (y == fullView && tableView.contentOffset.y == 0 && direction > 0) || (y == partialView) {
          tableView.isScrollEnabled = false
      } else {
        tableView.isScrollEnabled = true
      }

      return false
  }

CATATAN

Jika Anda mengatur .allowUserInteraction sebagai opsi animasi, seperti dalam proyek sampel, jadi Anda perlu mengaktifkan pengguliran pada penutupan penyelesaian animasi jika pengguna sedang menggulir ke atas.

Proyek Sampel

Saya membuat proyek sampel dengan lebih banyak opsi pada repo ini yang dapat memberi Anda wawasan yang lebih baik tentang bagaimana menyesuaikan aliran.

Dalam demo, fungsi addBottomSheetView () mengontrol tampilan mana yang harus digunakan sebagai lembar bawah.

Contoh Proyek Screenshot

- Tampilan Parsial

masukkan deskripsi gambar di sini

- Tampilan penuh

masukkan deskripsi gambar di sini

- Tampilan yang Dapat Digulir

masukkan deskripsi gambar di sini


3
Ini sebenarnya adalah tutorial yang bagus untuk childViews dan subViews. Terima kasih :)
Edison

@AhmedElassuty bagaimana saya bisa menambahkan tampilan tabel dalam xib dan memuat sebagai lembaran bawah? Jika Anda bisa membantu akan lebih baik Terima kasih sebelumnya!
nikhil nangia

3
@nikhilnangia Saya baru saja memperbarui repo dengan viewController lain "ScrollableBottomSheetViewController.swift" yang berisi tableView. Saya akan memperbarui jawabannya sesegera mungkin. Lihat ini juga github.com/AhmedElassuty/IOS-BottomSheet/issues/1
Ahmad Elassuty

12
Saya perhatikan bahwa lembar bawah Apple Maps menangani peralihan dari gerakan seret lembar ke gerakan gulir tampilan gulir dalam satu gerakan halus, yaitu pengguna tidak perlu menghentikan satu gerakan dan memulai yang baru untuk mulai menggulir tampilan. Contoh Anda tidak melakukan ini. Apakah Anda memiliki pemikiran tentang bagaimana hal itu dapat dicapai? Terima kasih, dan terima kasih banyak untuk memposting contoh dalam repo!
Stoph

2
@ RafaelaLourenço Saya sangat senang Anda menemukan jawaban saya bermanfaat! Terima kasih!
Ahmad Elassuty

55

Saya merilis perpustakaan berdasarkan jawaban saya di bawah ini.

Ini meniru overlay aplikasi Shortcuts. Lihat artikel ini untuk detailnya.

Komponen utama perpustakaan adalah OverlayContainerViewController. Ini mendefinisikan area di mana pengontrol tampilan dapat diseret ke atas dan ke bawah, menyembunyikan atau mengungkapkan konten di bawahnya.

let contentController = MapsViewController()
let overlayController = SearchViewController()

let containerController = OverlayContainerViewController()
containerController.delegate = self
containerController.viewControllers = [
    contentController,
    overlayController
]

window?.rootViewController = containerController

Terapkan OverlayContainerViewControllerDelegateuntuk menentukan jumlah takik yang diinginkan:

enum OverlayNotch: Int, CaseIterable {
    case minimum, medium, maximum
}

func numberOfNotches(in containerViewController: OverlayContainerViewController) -> Int {
    return OverlayNotch.allCases.count
}

func overlayContainerViewController(_ containerViewController: OverlayContainerViewController,
                                    heightForNotchAt index: Int,
                                    availableSpace: CGFloat) -> CGFloat {
    switch OverlayNotch.allCases[index] {
        case .maximum:
            return availableSpace * 3 / 4
        case .medium:
            return availableSpace / 2
        case .minimum:
            return availableSpace * 1 / 4
    }
}

Jawaban sebelumnya

Saya pikir ada poin penting yang tidak diperlakukan dalam solusi yang disarankan: transisi antara gulungan dan terjemahan.

Transisi peta antara gulir dan terjemahan

Di Maps, seperti yang mungkin telah Anda perhatikan, ketika tableView mencapai contentOffset.y == 0, lembar bawah akan naik atau turun.

Intinya rumit karena kita tidak bisa begitu saja mengaktifkan / menonaktifkan gulir ketika gerakan pan kami memulai terjemahan. Itu akan menghentikan gulir sampai sentuhan baru dimulai. Ini adalah kasus di sebagian besar solusi yang diusulkan di sini.

Ini adalah usaha saya untuk mengimplementasikan gerakan ini.

Titik awal: Aplikasi Maps

Untuk memulai penyelidikan kami, mari kita memvisualisasikan tampilan hirarki Maps (mulai Maps di simulator dan pilih Debug> Attach to process by PID or Name> Mapsdi Xcode 9).

Hirarki tampilan debug peta

Itu tidak mengatakan bagaimana gerakan itu bekerja, tetapi itu membantu saya untuk memahami logika itu. Anda dapat bermain dengan lldb dan debugger hierarki tampilan.

Tumpukan pengontrol tampilan kami

Mari kita buat versi dasar arsitektur Maps ViewController.

Kami mulai dengan BackgroundViewController(tampilan peta kami):

class BackgroundViewController: UIViewController {
    override func loadView() {
        view = MKMapView()
    }
}

Kami menempatkan tableView dalam dedicated UIViewController:

class OverlayViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    lazy var tableView = UITableView()

    override func loadView() {
        view = tableView
        tableView.dataSource = self
        tableView.delegate = self
    }

    [...]
}

Sekarang, kita membutuhkan VC untuk menyematkan overlay dan mengelola terjemahannya. Untuk menyederhanakan masalah, kami menganggapnya dapat menerjemahkan overlay dari satu titik statis OverlayPosition.maximumke titik lainnyaOverlayPosition.minimum .

Untuk saat ini ia hanya memiliki satu metode publik untuk menghidupkan perubahan posisi dan memiliki pandangan transparan:

enum OverlayPosition {
    case maximum, minimum
}

class OverlayContainerViewController: UIViewController {

    let overlayViewController: OverlayViewController
    var translatedViewHeightContraint = ...

    override func loadView() {
        view = UIView()
    }

    func moveOverlay(to position: OverlayPosition) {
        [...]
    }
}

Akhirnya kita membutuhkan ViewController untuk menanamkan semuanya:

class StackViewController: UIViewController {

    private var viewControllers: [UIViewController]

    override func viewDidLoad() {
        super.viewDidLoad()
        viewControllers.forEach { gz_addChild($0, in: view) }
    }
}

Di AppDelegate kami, urutan startup kami terlihat seperti:

let overlay = OverlayViewController()
let containerViewController = OverlayContainerViewController(overlayViewController: overlay)
let backgroundViewController = BackgroundViewController()
window?.rootViewController = StackViewController(viewControllers: [backgroundViewController, containerViewController])

Kesulitan di balik terjemahan overlay

Sekarang, bagaimana cara menerjemahkan overlay kami?

Sebagian besar solusi yang diajukan menggunakan pengenal isyarat pan khusus, tetapi kami sebenarnya sudah memilikinya: isyarat pan dari tampilan tabel. Selain itu, kita perlu menjaga agar gulungan dan terjemahannya tetap tersinkronisasi dan UIScrollViewDelegatememiliki semua acara yang kita butuhkan!

Implementasi naif akan menggunakan Gesture pan kedua dan mencoba untuk mereset contentOffsettampilan tabel ketika terjemahan terjadi:

func panGestureAction(_ recognizer: UIPanGestureRecognizer) {
    if isTranslating {
        tableView.contentOffset = .zero
    }
}

Tapi itu tidak berhasil. TableView memperbaruicontentOffset ketika tindakan pengidentifikasi gerakan pan sendiri memicu atau ketika panggilan balik displayLink disebut. Tidak ada peluang yang diakui pemicu kami tepat setelah mereka berhasil menimpa contentOffset. Satu-satunya kesempatan kami adalah mengambil bagian dari fase tata letak (dengan mengesampingkan layoutSubviewspanggilan tampilan gulir di setiap bingkai tampilan gulir) atau untuk menanggapi didScrollmetode delegasi yang dipanggil setiap kali contentOffsetdiubah. Ayo coba yang ini.

Implementasi terjemahan

Kami menambahkan delegasi ke OverlayVC untuk mengirimkan acara scrollview ke penterjemah terjemahan kami, yang OverlayContainerViewController:

protocol OverlayViewControllerDelegate: class {
    func scrollViewDidScroll(_ scrollView: UIScrollView)
    func scrollViewDidStopScrolling(_ scrollView: UIScrollView)
}

class OverlayViewController: UIViewController {

    [...]

    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        delegate?.scrollViewDidScroll(scrollView)
    }

    func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
        delegate?.scrollViewDidStopScrolling(scrollView)
    }
}

Dalam wadah kami, kami melacak terjemahan menggunakan enum:

enum OverlayInFlightPosition {
    case minimum
    case maximum
    case progressing
}

Perhitungan posisi saat ini terlihat seperti:

private var overlayInFlightPosition: OverlayInFlightPosition {
    let height = translatedViewHeightContraint.constant
    if height == maximumHeight {
        return .maximum
    } else if height == minimumHeight {
        return .minimum
    } else {
        return .progressing
    }
}

Kami membutuhkan 3 metode untuk menangani terjemahan:

Yang pertama memberi tahu kami jika kami perlu memulai terjemahan.

private func shouldTranslateView(following scrollView: UIScrollView) -> Bool {
    guard scrollView.isTracking else { return false }
    let offset = scrollView.contentOffset.y
    switch overlayInFlightPosition {
    case .maximum:
        return offset < 0
    case .minimum:
        return offset > 0
    case .progressing:
        return true
    }
}

Yang kedua melakukan terjemahan. Ini menggunakan translation(in:)metode gerakan pan scrollView.

private func translateView(following scrollView: UIScrollView) {
    scrollView.contentOffset = .zero
    let translation = translatedViewTargetHeight - scrollView.panGestureRecognizer.translation(in: view).y
    translatedViewHeightContraint.constant = max(
        Constant.minimumHeight,
        min(translation, Constant.maximumHeight)
    )
}

Yang ketiga menghidupkan akhir terjemahan ketika pengguna melepaskan jarinya. Kami menghitung posisi menggunakan kecepatan & posisi tampilan saat ini.

private func animateTranslationEnd() {
    let position: OverlayPosition =  // ... calculation based on the current overlay position & velocity
    moveOverlay(to: position)
}

Implementasi delegasi overlay kami terlihat seperti:

class OverlayContainerViewController: UIViewController {

    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        guard shouldTranslateView(following: scrollView) else { return }
        translateView(following: scrollView)
    }

    func scrollViewDidStopScrolling(_ scrollView: UIScrollView) {
        // prevent scroll animation when the translation animation ends
        scrollView.isEnabled = false
        scrollView.isEnabled = true
        animateTranslationEnd()
    }
}

Masalah terakhir: mengirimkan sentuhan penampung hamparan

Terjemahan sekarang cukup efisien. Tetapi masih ada masalah terakhir: sentuhan tidak dikirim ke tampilan latar belakang kita. Mereka semua dicegat oleh tampilan penampung hamparan. Kita tidak bisa mengatur isUserInteractionEnableduntuk falsekarena juga akan menonaktifkan interaksi dalam pandangan meja kami. Solusinya adalah yang digunakan secara besar-besaran dalam aplikasi Maps, PassThroughView:

class PassThroughView: UIView {
    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        let view = super.hitTest(point, with: event)
        if view == self {
            return nil
        }
        return view
    }
}

Ini menghilangkan dirinya sendiri dari rantai responden.

Dalam OverlayContainerViewController:

override func loadView() {
    view = PassThroughView()
}

Hasil

Inilah hasilnya:

Hasil

Anda dapat menemukan kode di sini .

Silakan jika Anda melihat ada bug, beri tahu saya! Perhatikan bahwa implementasi Anda tentu saja dapat menggunakan gerakan pan kedua, khususnya jika Anda menambahkan header di hamparan Anda.

Perbarui 23/08/18

Kami dapat mengganti scrollViewDidEndDraggingdengan willEndScrollingWithVelocityalih - alih enabling/ disablingscroll ketika pengguna berakhir menyeret:

func scrollView(_ scrollView: UIScrollView,
                willEndScrollingWithVelocity velocity: CGPoint,
                targetContentOffset: UnsafeMutablePointer<CGPoint>) {
    switch overlayInFlightPosition {
    case .maximum:
        break
    case .minimum, .progressing:
        targetContentOffset.pointee = .zero
    }
    animateTranslationEnd(following: scrollView)
}

Kita dapat menggunakan animasi pegas dan memungkinkan interaksi pengguna saat animasi untuk membuat gerakan mengalir lebih baik:

func moveOverlay(to position: OverlayPosition,
                 duration: TimeInterval,
                 velocity: CGPoint) {
    overlayPosition = position
    translatedViewHeightContraint.constant = translatedViewTargetHeight
    UIView.animate(
        withDuration: duration,
        delay: 0,
        usingSpringWithDamping: velocity.y == 0 ? 1 : 0.6,
        initialSpringVelocity: abs(velocity.y),
        options: [.allowUserInteraction],
        animations: {
            self.view.layoutIfNeeded()
    }, completion: nil)
}

Pendekatan ini tidak interaktif selama tahap animasi. Misalnya, di Maps, saya dapat menangkap lembar dengan jari saya saat itu mengembang. Saya kemudian dapat menggosok animasi dengan menggeser ke atas atau ke bawah. Ini akan kembali ke tempat mana pun yang terdekat. Saya percaya ini dapat diselesaikan menggunakan UIViewPropertyAnimator(yang memiliki kemampuan untuk berhenti sebentar), kemudian gunakan fractionCompleteproperti untuk melakukan scrub.
aust

1
Anda benar @ aust. Saya lupa mendorong perubahan saya sebelumnya. Seharusnya bagus sekarang. Terima kasih.
GaétanZ

Ini adalah ide yang bagus, namun saya dapat langsung melihat satu masalah. Dalam translateView(following:)metode Anda menghitung ketinggian berdasarkan terjemahan, tetapi itu bisa mulai dari nilai yang berbeda dari 0,0 (misalnya tampilan tabel digulir sedikit dan overlay dimaksimalkan ketika Anda mulai menyeret) . Itu akan menghasilkan lompatan awal. Anda bisa menyelesaikan ini dengan scrollViewWillBeginDraggingcallback di mana Anda akan mengingat inisial contentOffsettampilan tabel dan menggunakannya dalam translateView(following:)perhitungan.
Jakub Truhlář

1
@ GaétanZ Saya tertarik melampirkan debugger ke Maps.app di Simulator juga, tetapi mendapatkan kesalahan "Tidak dapat melampirkan pid:" 9276 "" diikuti dengan "Pastikan" Maps "belum berjalan, dan <username> memiliki izin untuk debug itu. " - Bagaimana Anda menipu Xcode untuk mengizinkan melampirkan ke Maps.app?
matm

1
@matm @ GaétanZ bekerja untuk saya di Xcode 10.1 / Mojave -> hanya perlu menonaktifkan untuk menonaktifkan System Integrity Protection (SIP). Anda perlu: 1) Mulai ulang mac Anda; 2) Tahan cmd + R; 3) Dari menu pilih Utilitas kemudian Terminal; 4) Dalam tipe window Terminal: csrutil disable && reboot. Anda kemudian akan memiliki semua kekuatan yang seharusnya diberikan root kepada Anda termasuk kemampuan untuk melampirkan ke proses Apple.
valdyr

18

Coba Pulley :

Pulley adalah perpustakaan laci yang mudah digunakan yang dimaksudkan untuk meniru laci di aplikasi Maps iOS 10. Itu memperlihatkan API sederhana yang memungkinkan Anda untuk menggunakan subkelas UIViewController sebagai konten laci atau konten utama.

Pratinjau Katrol

https://github.com/52inc/Pulley


1
Apakah ini mendukung pengguliran dalam daftar yang mendasarinya?
Richard Lindhout

@ RichardLindhout - Setelah menjalankan demo sepertinya mendukung gulir, tetapi bukan transisi yang lancar dari memindahkan laci ke menggulir daftar.
Stoph

Contohnya muncul untuk menyembunyikan tautan legal Apel di kiri bawah.
Gerd Castan

1
Pertanyaan super sederhana, bagaimana Anda mendapatkan indikator di bagian atas lembar bawah?
A Israfil

12

Anda dapat mencoba jawaban saya https://github.com/SCENEE/FloatingPanel . Ini menyediakan pengontrol tampilan wadah untuk menampilkan antarmuka "lembaran bawah".

Ini mudah digunakan dan Anda tidak keberatan penanganan pengenal isyarat! Anda juga dapat melacak tampilan gulir (atau tampilan saudara) di lembar bawah jika perlu.

Ini adalah contoh sederhana. Harap dicatat bahwa Anda perlu menyiapkan pengontrol tampilan untuk menampilkan konten Anda di lembar bawah.

import UIKit
import FloatingPanel

class ViewController: UIViewController {
    var fpc: FloatingPanelController!

    override func viewDidLoad() {
        super.viewDidLoad()

        fpc = FloatingPanelController()

        // Add "bottom sheet" in self.view.
        fpc.add(toParent: self)

        // Add a view controller to display your contents in "bottom sheet".
        let contentVC = ContentViewController()
        fpc.set(contentViewController: contentVC)

        // Track a scroll view in "bottom sheet" content if needed.
        fpc.track(scrollView: contentVC.tableView)    
    }
    ...
}

Berikut ini contoh kode lain untuk menampilkan lembar bawah untuk mencari lokasi seperti Apple Maps.

Contoh Aplikasi seperti Apple Maps


fpc.set (contentViewController: newsVC), metode yang hilang di perpustakaan
Faris Muhammed

1
Pertanyaan super sederhana, bagaimana Anda mendapatkan indikator di bagian atas lembar bawah?
A Israfil

1
@AIsrafil Saya pikir ini hanya UIView
ShadeToD

Saya pikir ini adalah solusi yang sangat bagus, tetapi ada masalah di iOS 13 dengan menghadirkan pengendali tampilan modal dengan panel mengambang ini.
ShadeToD

12

Saya menulis perpustakaan saya sendiri untuk mencapai perilaku yang dimaksud dalam aplikasi ios Maps. Ini adalah solusi berorientasi protokol. Jadi Anda tidak perlu mewarisi kelas dasar sebagai gantinya buat lembar pengontrol dan konfigurasikan sesuai keinginan. Ini juga mendukung navigasi dalam / presentasi dengan atau tanpa UINavigationController.

Lihat tautan di bawah untuk detail lebih lanjut.

https://github.com/OfTheWolf/UBottomSheet

lembar ubottom


INI harus menjadi jawaban yang dipilih, karena Anda masih dapat mengklik VC di belakang sembulan.
Jay

Pertanyaan super sederhana, bagaimana Anda mendapatkan indikator di bagian atas lembar bawah?
A Israfil

1

Saya baru-baru ini membuat komponen yang disebut SwipeableViewsebagai subclass of UIView, ditulis dalam Swift 5.1. Ini mendukung semua 4 arah, memiliki beberapa opsi penyesuaian dan dapat menghidupkan dan menyisipkan berbagai atribut dan item (seperti kendala tata letak, warna latar / warna, transformasi affine, saluran alfa, dan pusat tampilan, semuanya diperagakan dengan etalase masing-masing). Ini juga mendukung koordinasi menggesek dengan tampilan gulir dalam jika disetel atau terdeteksi secara otomatis. Harus cukup mudah dan mudah digunakan (saya harap 🙂)

Tautan di https://github.com/LucaIaco/SwipeableView

bukti dari konsep:

masukkan deskripsi gambar di sini

Semoga ini bisa membantu


0

Mungkin Anda dapat mencoba jawaban saya https://github.com/AnYuan/AYPannel , terinspirasi oleh Pulley. Transisi yang lancar dari memindahkan laci ke menggulir daftar. Saya menambahkan gerakan pan pada tampilan gulir wadah, dan mengatur shouldRecognizeSimurrentouslyWithGestureRecognizer untuk mengembalikan YA. Lebih detail di tautan github saya di atas. Ingin membantu.


6
Meskipun tautan ini dapat menjawab pertanyaan, lebih baik untuk memasukkan bagian-bagian penting dari jawaban di sini dan memberikan tautan untuk referensi. Jawaban hanya tautan dapat menjadi tidak valid jika halaman tertaut berubah. Meskipun tautan ini dapat menjawab pertanyaan, lebih baik untuk memasukkan bagian-bagian penting dari jawaban di sini dan memberikan tautan untuk referensi. Jawaban hanya tautan dapat menjadi tidak valid jika halaman tertaut berubah.
pirho
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.