Làm cách nào tôi có thể bắt chước trang dưới cùng từ ứng dụng Bản đồ?


202

Ai đó có thể cho tôi biết làm thế nào tôi có thể bắt chước bảng dưới cùng trong ứng dụng Bản đồ mới trong iOS 10 không?

Trong Android, bạn có thể sử dụng một BottomSheetmô phỏng hành vi này, nhưng tôi không thể tìm thấy bất cứ điều gì tương tự như vậy cho iOS.

Đó có phải là chế độ xem cuộn đơn giản với nội dung được chèn, sao cho thanh tìm kiếm ở dưới cùng?

Tôi còn khá mới với lập trình iOS nên nếu ai đó có thể giúp tôi tạo bố cục này, điều đó sẽ được đánh giá cao.

Đây là những gì tôi có nghĩa là "tấm dưới cùng":

ảnh chụp màn hình của tấm dưới cùng bị sụp đổ trong Bản đồ

ảnh chụp màn hình của bảng dưới cùng được mở rộng trong Bản đồ


1
Bạn phải tự xây dựng nó, tôi sợ. Đó là chế độ xem với chế độ xem nền mờ và một số nhận dạng cử chỉ.
Khánh Nguyễn

@KhanhNguyen yeah Tôi biết tôi phải tự xây dựng nó, nhưng điều tôi băn khoăn là những quan điểm nào được sử dụng để lưu trữ hiệu ứng này và cách chúng được đặt hàng, v.v.
qwertz

Đó là chế độ xem hiệu ứng hình ảnh với hiệu ứng mờ. Xem câu hỏi SO
Khánh Nguyễn

1
Tôi nghĩ rằng bạn có thể thêm một trình nhận dạng cử chỉ pan vào chế độ xem dưới cùng và di chuyển chế độ xem phù hợp (bằng cách quan sát các thay đổi bằng cách lưu trữ tọa độ y giữa các sự kiện của trình nhận dạng cử chỉ và tính toán sự khác biệt).
Khánh Nguyễn

2
Tôi thích câu hỏi của bạn. Tôi đang lên kế hoạch thực hiện một cái gì đó như thế này. Nếu ai đó có thể viết một số ví dụ sẽ tốt đẹp.
wviana

Câu trả lời:


330

Tôi không biết chính xác trang dưới cùng của ứng dụng Bản đồ mới, phản ứng thế nào với các tương tác của người dùng. Nhưng bạn có thể tạo chế độ xem tùy chỉnh trông giống như trong ảnh chụp màn hình và thêm nó vào chế độ xem chính.

Tôi giả sử bạn biết cách:

1- tạo bộ điều khiển xem bằng bảng phân cảnh hoặc sử dụng tệp xib.

2- sử dụng googleMaps hoặc MapKit của Apple.

Thí dụ

1- Tạo 2 bộ điều khiển xem, ví dụ: MapViewControllbottomSheetViewControll . Bộ điều khiển đầu tiên sẽ lưu trữ bản đồ và thứ hai là chính bảng dưới cùng.

Cấu hình MapViewControll

Tạo một phương thức để thêm khung nhìn dưới cùng.

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)
}

Và gọi nó trong phương thức viewDidAppear:

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

Cấu hình bottomSheetViewCont kiểm

1) Chuẩn bị nền

Tạo một phương thức để thêm hiệu ứng mờ và sống động

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)
}

gọi phương thức này trong viewWillAppear của bạn

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

Đảm bảo rằng màu nền của trình điều khiển của bạn là ClearColor.

2) Xuất hiện dưới cùng

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) Sửa đổi xib của bạn như bạn muốn.

4) Thêm Pan Gesture Recognizer vào chế độ xem của bạn.

Trong phương thức viewDidLoad của bạn, hãy thêm UIPanGestureRecognizer.

override func viewDidLoad() {
    super.viewDidLoad()

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

}

Và thực hiện hành vi cử chỉ của bạn:

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)
}

Tấm dưới cùng có thể cuộn:

Nếu chế độ xem tùy chỉnh của bạn là chế độ xem cuộn hoặc bất kỳ chế độ xem nào khác kế thừa từ đó, thì bạn có hai tùy chọn:

Đầu tiên:

Thiết kế chế độ xem với chế độ xem tiêu đề và thêm panGesture vào tiêu đề. (trải nghiệm người dùng xấu) .

Thứ hai:

1 - Thêm panGesture vào chế độ xem bảng dưới cùng.

2 - Triển khai UIGestureRecognizerDelegate và đặt đại biểu panGesture cho bộ điều khiển.

3- Thực hiện nên Nhận dạng đồng thời Với chức năng ủy nhiệm và vô hiệu hóa thuộc tính scrollView isScrollEnables trong hai trường hợp:

  • Quan điểm là một phần có thể nhìn thấy.
  • Chế độ xem hoàn toàn hiển thị, thuộc tính scrollView contentPackset là 0 và người dùng đang kéo chế độ xem xuống dưới.

Nếu không thì cho phép cuộn.

  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
  }

GHI CHÚ

Trong trường hợp bạn đặt .allowUserInteraction làm tùy chọn hoạt hình, như trong dự án mẫu, do đó bạn cần bật cuộn trên đóng hoàn thành hoạt hình nếu người dùng đang cuộn lên.

Dự án mẫu

Tôi tạo ra một dự án mẫu với các tùy chọn thêm về này repo có thể giúp bạn hiểu rõ hơn về cách tùy chỉnh dòng chảy.

Trong bản demo, hàm addBottomSheetView () kiểm soát chế độ xem nào sẽ được sử dụng làm bảng dưới cùng.

Ảnh chụp màn hình dự án mẫu

- Tầm nhìn hạn chế

nhập mô tả hình ảnh ở đây

- Toàn cảnh

nhập mô tả hình ảnh ở đây

- Chế độ xem có thể cuộn

nhập mô tả hình ảnh ở đây


3
Đây thực sự là một hướng dẫn tốt cho childViews và subViews. Cảm ơn bạn :)
Edison

@AhmedElassuty làm thế nào tôi có thể thêm chế độ xem bảng trong xib và tải dưới dạng bảng dưới cùng? Nếu bạn có thể giúp đỡ sẽ rất tuyệt Cảm ơn trước!
nikhil nangia

3
@nikhilnangia Tôi vừa cập nhật repo với một viewContoder khác "ScrollableBottomSheetViewContoder.swift" có chứa một bảngView. Tôi sẽ cập nhật câu trả lời sớm nhất có thể. Kiểm tra điều này quá github.com/AhmedElassuty/IOS-BottomSheet/issues/1
Ahmad Elassuty

12
Tôi nhận thấy rằng trang dưới cùng của Apple Maps xử lý việc chuyển từ cử chỉ kéo trang sang cử chỉ cuộn cuộn trong một chuyển động mượt mà, tức là người dùng không cần dừng một cử chỉ và bắt đầu một cử chỉ mới để bắt đầu cuộn chế độ xem. Ví dụ của bạn không làm điều này. Bạn có bất kỳ suy nghĩ về làm thế nào có thể được thực hiện? Cảm ơn, và cảm ơn rất nhiều vì đã đăng ví dụ trong một repo!
Stoph

2
@ RafaelaLourenço Tôi thực sự rất vui khi bạn thấy câu trả lời của tôi hữu ích! Cảm ơn bạn!
Ahmad Elassuty

55

Tôi đã phát hành một thư viện dựa trên câu trả lời của tôi dưới đây.

Nó bắt chước lớp phủ ứng dụng Phím tắt. Xem bài viết này để biết chi tiết.

Thành phần chính của thư viện là OverlayContainerViewController. Nó xác định một khu vực nơi một bộ điều khiển xem có thể được kéo lên xuống, ẩn hoặc tiết lộ nội dung bên dưới nó.

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

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

window?.rootViewController = containerController

Thực hiện OverlayContainerViewControllerDelegateđể xác định số lượng notch mong muốn:

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

Câu trả lời trước

Tôi nghĩ có một điểm quan trọng không được xử lý trong các giải pháp được đề xuất: sự chuyển đổi giữa cuộn và bản dịch.

Bản đồ chuyển đổi giữa cuộn và bản dịch

Trong Bản đồ, như bạn có thể nhận thấy, khi bảngView đến contentOffset.y == 0, bảng dưới cùng sẽ trượt lên hoặc đi xuống.

Vấn đề là khó khăn vì chúng ta không thể đơn giản bật / tắt cuộn khi cử chỉ pan của chúng ta bắt đầu dịch. Nó sẽ dừng cuộn cho đến khi một liên lạc mới bắt đầu. Đây là trường hợp trong hầu hết các giải pháp được đề xuất ở đây.

Đây là nỗ lực của tôi để thực hiện chuyển động này.

Điểm bắt đầu: Ứng dụng Bản đồ

Để bắt đầu cuộc điều tra của chúng tôi, chúng ta hãy hình dung hệ thống phân cấp quan điểm của Maps (bắt đầu Maps trên một mô phỏng và chọn Debug> Attach to process by PID or Name> Mapstrong Xcode 9).

Bản đồ gỡ lỗi xem phân cấp

Nó không cho biết chuyển động hoạt động như thế nào, nhưng nó giúp tôi hiểu logic của nó. Bạn có thể chơi với lldb và trình gỡ lỗi phân cấp xem.

Ngăn xếp điều khiển xem của chúng tôi

Hãy tạo một phiên bản cơ bản của kiến ​​trúc Maps ViewControll.

Chúng tôi bắt đầu với một BackgroundViewController(chế độ xem bản đồ của chúng tôi):

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

Chúng tôi đặt bảngView trong một chuyên dụng UIViewController:

class OverlayViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    lazy var tableView = UITableView()

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

    [...]
}

Bây giờ, chúng ta cần một VC để nhúng lớp phủ và quản lý bản dịch của nó. Để đơn giản hóa vấn đề, chúng tôi xem xét rằng nó có thể dịch lớp phủ từ điểm tĩnh này OverlayPosition.maximumsang điểm tĩnh khác OverlayPosition.minimum.

Cho đến nay, nó chỉ có một phương thức công khai để làm thay đổi vị trí và nó có chế độ xem minh bạch:

enum OverlayPosition {
    case maximum, minimum
}

class OverlayContainerViewController: UIViewController {

    let overlayViewController: OverlayViewController
    var translatedViewHeightContraint = ...

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

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

Cuối cùng, chúng ta cần một ViewContoder để nhúng tất cả:

class StackViewController: UIViewController {

    private var viewControllers: [UIViewController]

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

Trong AppDelegate, chuỗi khởi động của chúng tôi trông như sau:

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

Khó khăn đằng sau bản dịch lớp phủ

Bây giờ, làm thế nào để dịch lớp phủ của chúng tôi?

Hầu hết các giải pháp được đề xuất đều sử dụng bộ nhận dạng cử chỉ pan chuyên dụng, nhưng chúng tôi thực sự đã có một: cử chỉ pan của chế độ xem bảng. Hơn nữa, chúng tôi cần giữ cho cuộn và bản dịch được đồng bộ hóa và UIScrollViewDelegatecó tất cả các sự kiện chúng tôi cần!

Việc triển khai ngây thơ sẽ sử dụng Gesture pan thứ hai và cố gắng đặt lại contentOffsetchế độ xem bảng khi bản dịch xảy ra:

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

Nhưng nó không hoạt động. TableView cập nhật contentOffsetkhi kích hoạt hành động nhận dạng cử chỉ pan của chính nó hoặc khi gọi lại displayLink của nó được gọi. Không có cơ hội mà trình nhận dạng của chúng tôi kích hoạt ngay sau khi những người đó ghi đè thành công contentOffset. Cơ hội duy nhất của chúng tôi là tham gia vào giai đoạn bố trí (bằng cách ghi đè layoutSubviewscác lệnh gọi xem cuộn ở mỗi khung của chế độ xem cuộn) hoặc để đáp ứng didScrollphương thức của đại biểu được gọi mỗi lần contentOffsetsửa đổi. Hãy thử cái này.

Việc thực hiện dịch thuật

Chúng tôi thêm một đại biểu để OverlayVCgửi các sự kiện của scrollview đến bộ xử lý dịch của chúng tôi, đó là 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)
    }
}

Trong thùng chứa của chúng tôi, chúng tôi theo dõi bản dịch bằng enum:

enum OverlayInFlightPosition {
    case minimum
    case maximum
    case progressing
}

Tính toán vị trí hiện tại trông như sau:

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

Chúng tôi cần 3 phương pháp để xử lý bản dịch:

Điều đầu tiên cho chúng ta biết nếu chúng ta cần bắt đầu dịch.

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

Người thứ hai thực hiện việc dịch thuật. Nó sử dụng translation(in:)phương thức cử chỉ pan của 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)
    )
}

Cái thứ ba hoạt hình kết thúc bản dịch khi người dùng thả ngón tay ra. Chúng tôi tính toán vị trí bằng cách sử dụng vận tốc và vị trí hiện tại của chế độ xem.

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

Việc triển khai đại biểu của lớp phủ của chúng tôi chỉ đơn giản là trông như sau:

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()
    }
}

Vấn đề cuối cùng: gửi các liên lạc của lớp phủ

Bản dịch bây giờ khá hiệu quả. Nhưng vẫn còn một vấn đề cuối cùng: các cú chạm không được chuyển đến chế độ xem nền của chúng tôi. Tất cả đều bị chặn bởi chế độ xem của lớp phủ. Chúng tôi không thể đặt isUserInteractionEnabledthành falsevì nó cũng sẽ vô hiệu hóa tương tác trong chế độ xem bảng của chúng tôi. Giải pháp là giải pháp được sử dụng ồ ạt trong ứng dụng Bản đồ , 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
    }
}

Nó loại bỏ chính nó khỏi chuỗi phản hồi.

Trong OverlayContainerViewController:

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

Kết quả

Đây là kết quả:

Kết quả

Bạn có thể tìm thấy mã ở đây .

Xin vui lòng nếu bạn thấy bất kỳ lỗi, cho tôi biết! Lưu ý rằng việc triển khai của bạn tất nhiên có thể sử dụng cử chỉ pan thứ hai, đặc biệt nếu bạn thêm tiêu đề trong lớp phủ của mình.

Cập nhật ngày 23/08/18

Chúng tôi có thể thay thế scrollViewDidEndDraggingbằng willEndScrollingWithVelocitythay vì enabling/ disablingcuộn khi người dùng kết thúc kéo:

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

Chúng ta có thể sử dụng hoạt hình mùa xuân và cho phép người dùng tương tác trong khi hoạt hình để làm cho chuyển động tốt hơn:

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)
}

Cách tiếp cận này không tương tác trong các giai đoạn hoạt hình. Ví dụ: trong Bản đồ, tôi có thể bắt lấy tờ bằng ngón tay khi nó đang mở rộng. Sau đó tôi có thể chà hoạt hình bằng cách xoay lên hoặc xuống. Nó sẽ trở về bất cứ nơi nào gần nhất. Tôi tin rằng điều này có thể được giải quyết bằng cách sử dụng UIViewPropertyAnimator(có khả năng tạm dừng), sau đó sử dụng thuộc fractionCompletetính để thực hiện chà.
aust

1
Bạn nói đúng @aust. Tôi quên đẩy sự thay đổi trước đây của tôi. Nó nên được tốt bây giờ. Cảm ơn.
GaétanZ

Đây là một ý tưởng tuyệt vời, tuy nhiên tôi có thể thấy một vấn đề ngay lập tức. Trong translateView(following:)phương pháp bạn tính toán chiều cao dựa trên bản dịch, nhưng có thể bắt đầu từ một giá trị khác với 0,0 (ví dụ: Chế độ xem bảng được cuộn một chút và lớp phủ được tối đa hóa khi bạn bắt đầu kéo) . Điều đó sẽ dẫn đến bước nhảy ban đầu. Bạn có thể giải quyết điều này bằng cách scrollViewWillBeginDragginggọi lại nơi bạn sẽ nhớ ban đầu contentOffsetcủa chế độ xem bảng và sử dụng nó trong translateView(following:)tính toán.
Jakub Truhlář

1
@ GaétanZ Tôi cũng quan tâm đến việc đính kèm trình gỡ lỗi cho Maps.app trên Trình mô phỏng, nhưng gặp lỗi "Không thể đính kèm với pid: mật 9276 gỡ lỗi nó. " - Bạn đã lừa Xcode như thế nào để cho phép đính kèm vào Maps.app?
matm

1
@matm @ GaétanZ làm việc cho tôi trên Xcode 10.1 / Mojave -> chỉ cần tắt để vô hiệu hóa Bảo vệ toàn vẹn hệ thống (SIP). Bạn cần phải: 1) Khởi động lại máy mac của bạn; 2) Giữ cmd + R; 3) Từ menu chọn Tiện ích rồi Terminal; 4) Trong loại cửa sổ Terminal : csrutil disable && reboot. Sau đó, bạn sẽ có tất cả các quyền mà root thường sẽ cung cấp cho bạn bao gồm cả khả năng gắn vào quy trình của Apple.
valdyr

18

Hãy thử ròng rọc :

Pulley là một thư viện ngăn kéo dễ sử dụng có nghĩa là bắt chước ngăn kéo trong ứng dụng Bản đồ của iOS 10. Nó hiển thị một API đơn giản cho phép bạn sử dụng bất kỳ lớp con UIViewControll nào làm nội dung ngăn kéo hoặc nội dung chính.

Xem trước ròng rọc

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


1
Nó có hỗ trợ cuộn trong danh sách bên dưới không?
Richard Lindhout

@RichardLindhout - Sau khi chạy bản demo, có vẻ như nó hỗ trợ cuộn, nhưng không phải là sự chuyển đổi suôn sẻ từ việc chuyển ngăn kéo sang cuộn danh sách.
Stoph

Ví dụ xuất hiện để ẩn liên kết pháp lý Táo ở phía dưới bên trái.
Gerd Castan

1
Câu hỏi siêu đơn giản, làm thế nào bạn có được chỉ số ở trên cùng của bảng dưới cùng?
Một Israfil

12

Bạn có thể thử câu trả lời của tôi https://github.com/SCENEE/FloatingPanel . Nó cung cấp một bộ điều khiển xem container để hiển thị giao diện "bảng dưới cùng".

Thật dễ dàng để sử dụng và bạn không bận tâm đến bất kỳ thao tác nhận dạng cử chỉ nào! Ngoài ra, bạn có thể theo dõi chế độ xem cuộn (hoặc chế độ xem anh chị em) trong bảng dưới cùng nếu cần.

Đây là một ví dụ đơn giản. Xin lưu ý rằng bạn cần chuẩn bị một bộ điều khiển xem để hiển thị nội dung của bạn trong một bảng dưới cùng.

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)    
    }
    ...
}

Dưới đây là một mã ví dụ khác để hiển thị bảng dưới cùng để tìm kiếm một vị trí như Apple Maps.

Ứng dụng mẫu như Apple Maps


fpc.set (contentViewControll: newsVC), phương thức bị thiếu trong thư viện
Faris Muhammed

1
Câu hỏi siêu đơn giản, làm thế nào bạn có được chỉ số ở trên cùng của bảng dưới cùng?
Một Israfil

1
@AIsrafil Tôi nghĩ rằng nó chỉ là một UIView
ShadowToD

Tôi nghĩ rằng đó là một giải pháp thực sự tốt, nhưng có một vấn đề trong iOS 13 với việc trình bày bộ điều khiển chế độ xem theo chế độ với bảng điều khiển nổi này.
ShadowToD

12

Tôi đã viết thư viện của riêng mình để đạt được hành vi dự định trong ứng dụng Bản đồ ios. Nó là một giải pháp định hướng giao thức. Vì vậy, bạn không cần phải kế thừa bất kỳ lớp cơ sở nào thay vào đó hãy tạo bộ điều khiển trang tính và định cấu hình theo ý muốn. Nó cũng hỗ trợ điều hướng / trình bày bên trong có hoặc không có UINavestionControll.

Xem liên kết dưới đây để biết thêm chi tiết.

https://github.com/OfTheWolf/UBottomSheet

tấm ubottom


Đây phải là câu trả lời được chọn, vì bạn vẫn có thể nhấp vào VC phía sau cửa sổ bật lên.
Jay

Câu hỏi siêu đơn giản, làm thế nào bạn có được chỉ số ở trên cùng của bảng dưới cùng?
Một Israfil

1

Gần đây tôi đã tạo ra một thành phần được gọi SwipeableViewlà lớp con của UIView, được viết trong Swift 5.1. Nó hỗ trợ tất cả 4 hướng, có một số tùy chọn tùy chỉnh và có thể làm động và nội suy các thuộc tính và mục khác nhau (như ràng buộc bố cục, màu nền / màu, biến đổi affine, kênh alpha và trung tâm xem, tất cả đều được trình diễn với trường hợp hiển thị tương ứng). Nó cũng hỗ trợ phối hợp vuốt với chế độ xem cuộn bên trong nếu được đặt hoặc tự động phát hiện. Nên khá dễ dàng và đơn giản để sử dụng (tôi hy vọng)

Liên kết tại https://github.com/LucaIaco/SwipizableView

bằng chứng của khái niệm:

nhập mô tả hình ảnh ở đây

Hy vọng nó giúp


0

Có lẽ bạn có thể thử câu trả lời của tôi https://github.com/AnYuan/AYPannel , lấy cảm hứng từ Pulley. Chuyển đổi suôn sẻ từ việc di chuyển ngăn kéo sang cuộn danh sách. Tôi đã thêm một cử chỉ pan trên chế độ xem cuộn chứa và đặt nênRecognizeSim đồng thờiWithGestureRecognizer để trả về CÓ. Chi tiết hơn trong liên kết github của tôi ở trên. Mong giúp đỡ.


6
Mặc dù liên kết này có thể trả lời câu hỏi, tốt hơn là bao gồm các phần thiết yếu của câu trả lời ở đây và cung cấp liên kết để tham khảo. Câu trả lời chỉ liên kết có thể trở nên không hợp lệ nếu trang được liên kết thay đổi. Mặc dù liên kết này có thể trả lời câu hỏi, tốt hơn là bao gồm các phần thiết yếu của câu trả lời ở đây và cung cấp liên kết để tham khảo. Câu trả lời chỉ liên kết có thể trở nên không hợp lệ nếu trang được liên kết thay đổi.
pirho
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.