मैं मैप्स ऐप से नीचे की शीट की नकल कैसे कर सकता हूं?


202

क्या कोई मुझे बता सकता है कि मैं iOS 10 में नए मैप्स ऐप में नीचे की शीट की नकल कैसे कर सकता हूं?

एंड्रॉइड में, आप BottomSheetइस व्यवहार की नकल कर सकते हैं , लेकिन मुझे iOS के लिए ऐसा कुछ नहीं मिला।

क्या सामग्री इनसेट के साथ एक साधारण स्क्रॉल दृश्य है, ताकि खोज पट्टी नीचे है?

मैं iOS प्रोग्रामिंग के लिए काफी नया हूं, अगर कोई मुझे इस लेआउट को बनाने में मदद कर सकता है, तो इसकी बहुत सराहना की जाएगी।

यह मेरा मतलब है "नीचे शीट" द्वारा:

मैप्स में ढह गई निचली शीट का स्क्रीनशॉट

मैप्स में विस्तारित नीचे की शीट का स्क्रीनशॉट


1
आपको इसका निर्माण खुद करना है मुझे डर है। यह धुंधला पृष्ठभूमि दृश्य और कुछ हावभाव पहचानकर्ताओं के साथ एक दृश्य है।
खान न्ग्येन

@KhanhNguyen हाँ, मुझे पता है कि मुझे इसे स्वयं बनाना है, लेकिन जो मैं सोच रहा हूँ वह इस आशय को दर्शाने के लिए उपयोग किया जाता है और वे कैसे आदेशित होते हैं इत्यादि
qwertz

यह धब्बा प्रभाव के साथ दृश्य प्रभाव दृश्य है। इस SO प्रश्न को
ख़ान गुयेन

1
मुझे लगता है कि आप एक पैन जेस्चर पहचानकर्ता को नीचे के दृश्य में जोड़ सकते हैं और उसके अनुसार दृश्य को स्थानांतरित कर सकते हैं (इशारों को पहचानने वाले की घटनाओं के बीच y निर्देशांक को संग्रहीत करके और अंतर की गणना करके परिवर्तनों को देखते हुए)।
खान गुयेन

2
मुझे आपके सवाल पसंद हैं। मैं कुछ इस तरह से लागू करने की योजना बना रहा हूं। अगर कोई कुछ उदाहरण लिख सकता है तो अच्छा होगा।
विएना

जवाबों:


329

मुझे नहीं पता कि नए मैप्स ऐप की सबसे नीचे की शीट, उपयोगकर्ता के इंटरैक्शन का जवाब कैसे देती है। लेकिन आप एक कस्टम दृश्य बना सकते हैं जो स्क्रीनशॉट में एक जैसा दिखता है और इसे मुख्य दृश्य में जोड़ देता है।

मुझे लगता है आप जानते हैं कि कैसे:

1- स्टोरीबोर्ड द्वारा या xib फ़ाइलों का उपयोग करके व्यू कंट्रोलर बनाएं।

2- googleMaps या Apple के MapKit का उपयोग करें।

उदाहरण

1- उदाहरण के लिए 2 व्यू कंट्रोलर बनाएं, मैपव्यूकंट्रोलर और बॉटमशीट व्यू कंट्रोलर । पहला नियंत्रक नक्शे की मेजबानी करेगा और दूसरा नीचे की शीट है।

MapViewController कॉन्फ़िगर करें

नीचे शीट दृश्य को जोड़ने के लिए एक विधि बनाएं।

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

और इसे viewDidAppear विधि में कॉल करें:

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

बॉटमशीट को देखें कॉन्फ़िगर करेंकंट्रोलर

1) पृष्ठभूमि तैयार करें

धुंधला और जीवंत प्रभाव जोड़ने के लिए एक विधि बनाएं

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

इस विधि को अपने viewWillAppear में कॉल करें

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

सुनिश्चित करें कि आपके नियंत्रक का दृश्य पृष्ठभूमि रंग स्पष्ट है।

2) चेतन तलछट उपस्थिति

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) अपने xib को संशोधित करें जैसा आप चाहते हैं।

4) अपने दृष्टिकोण में पैन जेस्चर पहचानकर्ता जोड़ें।

अपने विचार मेंDidLoad विधि UIPanGestureRecognizer जोड़ें।

override func viewDidLoad() {
    super.viewDidLoad()

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

}

और अपने हावभाव व्यवहार को लागू करें:

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

स्क्रॉल करने योग्य निचली शीट:

यदि आपका कस्टम दृश्य एक स्क्रॉल दृश्य या कोई अन्य दृश्य है जो इनहेरिट करता है, तो आपके पास दो विकल्प हैं:

प्रथम:

हेडर दृश्य के साथ दृश्य डिज़ाइन करें और हेडर में पैनग्योर जोड़ें। (बुरा उपयोगकर्ता अनुभव)

दूसरा:

1 - पैन शीट को नीचे शीट दृश्य में जोड़ें।

2 - UIGestureRecognizerDelegate लागू करें और नियंत्रक के लिए panGesture प्रतिनिधि सेट करें।

3 - कार्यान्वयन को लागू करेंसामान्य रूप से प्रतिनिधि कार्य के साथ और स्क्रॉल दृश्य को अक्षम करें । दो मामलों में सक्षम संपत्ति है:

  • दृश्य आंशिक रूप से दिखाई देता है।
  • दृश्य पूरी तरह से दिखाई देता है, स्क्रॉलव्यू सामग्रीऑफसेट संपत्ति 0 है और उपयोगकर्ता दृश्य को नीचे की ओर खींच रहा है।

अन्यथा स्क्रॉलिंग सक्षम करें।

  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
  }

ध्यान दें

यदि आप नमूना परियोजना की तरह एक एनीमेशन विकल्प के रूप में .allowUserInteraction सेट करते हैं , तो आपको उपयोगकर्ता को स्क्रॉल करने पर एनीमेशन पूर्णता समापन पर स्क्रॉल करने में सक्षम करने की आवश्यकता है।

नमूना परियोजना

मैंने इस रेपो पर अधिक विकल्पों के साथ एक नमूना परियोजना बनाई जो प्रवाह को अनुकूलित करने के तरीके के बारे में आपको बेहतर जानकारी दे सकती है।

डेमो में, addBottomSheetView () फ़ंक्शन नियंत्रण जो दृश्य को एक निचली शीट के रूप में उपयोग किया जाना चाहिए।

नमूना परियोजना स्क्रीनशॉट

- आंशिक दृश्य

यहां छवि विवरण दर्ज करें

- पूरा दृश्य

यहां छवि विवरण दर्ज करें

- स्क्रॉल करने योग्य दृश्य

यहां छवि विवरण दर्ज करें


3
यह वास्तव में चाइल्ड व्यू और सब व्यू के लिए एक अच्छा ट्यूटोरियल है।
एडिसन

@AhmedElassuty मैं xib में टेबलव्यू कैसे जोड़ सकता हूं और नीचे की शीट के रूप में लोड कर सकता हूं? यदि आप मदद कर सकते हैं तो बहुत अच्छा होगा अग्रिम धन्यवाद!
निखिल नांगिया

3
@nikhilnangia I ने रेपो को सिर्फ एक अन्य दृश्य के साथ अपडेट किया है "स्क्रॉलेबलबॉटसमस्केटशीटव्यूकंट्रोलर.स्विफ्ट" जिसमें एक टेबल व्यू है। मैं जल्द से जल्द जवाब अपडेट कर दूंगा। इसे भी चेक करें github.com/AhmedElassuty/IOS-BottomSheet/issues/1
अहमद एलासूट

12
मैंने देखा कि ऐप्पल मैप्स की निचली शीट शीट ड्रैग जेस्चर से स्क्रॉल व्यू इशारे को एक चिकनी गति में बदलने का काम करती है, यानी उपयोगकर्ता को एक इशारे को रोकने और व्यू स्क्रॉल शुरू करने के लिए एक नया स्टार्ट करने की आवश्यकता नहीं है। आपका उदाहरण ऐसा नहीं करता है। क्या आपके पास कोई विचार है कि कैसे पूरा किया जा सकता है? धन्यवाद, और रेपो में उदाहरण पोस्ट करने के लिए एक टन धन्यवाद!
स्टोफ

2
@ RafaelaLourenço मैं वास्तव में खुश हूं कि आपको मेरा उत्तर मददगार लगा! धन्यवाद!
अहमद इलासुत

55

मैंने नीचे अपने उत्तर के आधार पर एक पुस्तकालय जारी किया ।

यह शॉर्टकट एप्लिकेशन ओवरले की नकल करता है। देखें इस लेख जानकारी के लिए।

पुस्तकालय का मुख्य घटक पुस्तकालय है OverlayContainerViewController। यह एक क्षेत्र को परिभाषित करता है जहां एक दृश्य नियंत्रक को ऊपर और नीचे खींचा जा सकता है, इसके नीचे की सामग्री को छिपा या प्रकट कर सकता है।

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

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

window?.rootViewController = containerController

OverlayContainerViewControllerDelegateकाश की संख्या निर्दिष्ट करने के लिए लागू करें:

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

पिछला उत्तर

मुझे लगता है कि एक महत्वपूर्ण बिंदु है जो सुझाए गए समाधानों में व्यवहार नहीं किया जाता है: स्क्रॉल और अनुवाद के बीच संक्रमण।

स्क्रॉल और अनुवाद के बीच मैप्स का संक्रमण

मैप्स में, जैसा कि आपने देखा होगा, जब टेबल व्यू पहुंचता है contentOffset.y == 0, तो नीचे की शीट या तो स्लाइड करती है या नीचे जाती है।

जब हम हमारे पैन जेस्चर का अनुवाद शुरू करते हैं तो हम इस बिंदु पर मुश्किल हो जाते हैं क्योंकि हम बस स्क्रॉल को सक्षम / अक्षम नहीं कर सकते हैं। यह एक नया स्पर्श शुरू होने तक स्क्रॉल को रोक देगा। यहाँ अधिकांश प्रस्तावित समाधानों में यही स्थिति है।

यहाँ इस प्रस्ताव को लागू करने का मेरा प्रयास है।

प्रारंभिक बिंदु: मैप्स ऐप

हमारी जांच शुरू करने के लिए, चलो नक्शे को देखते पदानुक्रम कल्पना (एक सिम्युलेटर पर मानचित्र प्रारंभ करें और चयन Debug> Attach to process by PID or Name> MapsXcode 9 में)।

मानचित्र डीबग दृश्य पदानुक्रम

यह नहीं बताता कि गति कैसे काम करती है, लेकिन इसने मुझे इसके तर्क को समझने में मदद की। आप एलडीबी और व्यू पदानुक्रम डिबगर के साथ खेल सकते हैं।

हमारे दृश्य नियंत्रक ढेर

चलो मैप्स व्यू कंट्रोलर आर्किटेक्चर का एक मूल संस्करण बनाते हैं।

हम एक BackgroundViewController(हमारे मानचित्र दृश्य) से शुरू करते हैं :

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

हम एक समर्पित में tableView डालते हैं UIViewController:

class OverlayViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    lazy var tableView = UITableView()

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

    [...]
}

अब, हमें ओवरले को एम्बेड करने और इसके अनुवाद को प्रबंधित करने के लिए VC की आवश्यकता है। समस्या को सरल बनाने के लिए, हम मानते हैं कि यह ओवरले को एक स्थिर बिंदु OverlayPosition.maximumसे दूसरे में अनुवाद कर सकता है OverlayPosition.minimum

अभी के लिए यह स्थिति परिवर्तन को चेतन करने के लिए केवल एक सार्वजनिक विधि है और इसमें एक पारदर्शी दृष्टिकोण है:

enum OverlayPosition {
    case maximum, minimum
}

class OverlayContainerViewController: UIViewController {

    let overlayViewController: OverlayViewController
    var translatedViewHeightContraint = ...

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

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

अंत में हम सभी को एम्बेड करने के लिए ViewController की जरूरत है:

class StackViewController: UIViewController {

    private var viewControllers: [UIViewController]

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

हमारे AppDelegate में, हमारा स्टार्टअप अनुक्रम इस तरह दिखता है:

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

ओवरले अनुवाद के पीछे की कठिनाई

अब, हमारे ओवरले का अनुवाद कैसे करें?

प्रस्तावित समाधानों में से अधिकांश एक समर्पित पैन जेस्चर पहचानकर्ता का उपयोग करते हैं, लेकिन हमारे पास वास्तव में पहले से ही एक है: टेबल व्यू का पैन जेस्चर। इसके अलावा, हमें स्क्रॉल और अनुवाद को समन्‍वयित रखने की आवश्‍यकता है और UIScrollViewDelegateहमें उन सभी घटनाओं की आवश्‍यकता है!

एक भोली कार्यान्वयन एक दूसरे पैन जेस्चर का उपयोग करेगा और contentOffsetअनुवाद होने पर तालिका दृश्य को रीसेट करने का प्रयास करेगा :

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

लेकिन यह काम नहीं करता है। contentOffsetजब अपने स्वयं के पैन जेस्चर पहचानकर्ता कार्रवाई ट्रिगर होती है या जब इसका डिस्प्लेलिंक कॉलबैक कहा जाता है, तो टेबल व्यू इसे अपडेट करता है। ऐसा कोई मौका नहीं है कि हमारे पहचानकर्ता सफलतापूर्वक ओवरराइड करने के लिए सही होने के बाद ट्रिगर होते हैं contentOffset। हमारा एकमात्र मौका या तो लेआउट चरण का हिस्सा लेना है ( layoutSubviewsस्क्रॉल दृश्य के प्रत्येक फ्रेम पर स्क्रॉल दृश्य कॉल को ओवरराइड करके ) या didScrollप्रत्येक बार contentOffsetसंशोधित किए गए प्रतिनिधि के तरीके का जवाब देने के लिए । चलो यह एक कोशिश करो।

अनुवाद कार्यान्वयन

हम OverlayVCअपने अनुवाद हैंडलर को स्क्रॉलव्यू की घटनाओं को भेजने के लिए अपने प्रतिनिधि को जोड़ते हैं 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)
    }
}

हमारे कंटेनर में, हम एक एनम का उपयोग करके अनुवाद का ट्रैक रखते हैं:

enum OverlayInFlightPosition {
    case minimum
    case maximum
    case progressing
}

वर्तमान स्थिति गणना इस तरह दिखती है:

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

अनुवाद को संभालने के लिए हमें 3 विधियों की आवश्यकता है:

पहले एक हमें बताता है कि क्या हमें अनुवाद शुरू करने की आवश्यकता है।

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

दूसरा अनुवाद करता है। यह translation(in:)स्क्रॉलव्यू के पैन जेस्चर की विधि का उपयोग करता है ।

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

तीसरा जब उपयोगकर्ता अपनी उंगली जारी करता है, तो अनुवाद का अंत एनिमेट करता है। हम वेग और दृश्य की वर्तमान स्थिति का उपयोग करके स्थिति की गणना करते हैं।

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

हमारे उपरिशायी प्रतिनिधि के कार्यान्वयन की तरह दिखता है:

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

अंतिम समस्या: ओवरले कंटेनर के स्पर्शों को भेजना

अनुवाद अब बहुत कुशल है। लेकिन अभी भी एक अंतिम समस्या है: स्पर्श हमारे पृष्ठभूमि दृश्य में वितरित नहीं किए गए हैं। वे सभी ओवरले कंटेनर के दृष्टिकोण से इंटरसेप्टेड हैं। हम निर्धारित नहीं कर सकते isUserInteractionEnabledकरने के लिए false, क्योंकि यह भी हमारे तालिका दृश्य में बातचीत को निष्क्रिय होगा। समाधान मैप्स ऐप में बड़े पैमाने पर उपयोग किया जाता है 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
    }
}

यह रिस्पोंडर श्रृंखला से खुद को हटा देता है।

इन OverlayContainerViewController:

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

परिणाम

यहाँ परिणाम है:

परिणाम

आप यहां कोड पा सकते हैं ।

कृपया यदि आपको कोई बग दिखाई दे, तो मुझे बताएं! ध्यान दें कि आपका कार्यान्वयन निश्चित रूप से एक दूसरे पैन जेस्चर का उपयोग कर सकता है, खासकर यदि आप अपने ओवरले में एक हेडर जोड़ते हैं।

अपडेट 23/08/18

हम जगह ले सकता है scrollViewDidEndDraggingके साथ willEndScrollingWithVelocityके बजाय enabling/ disablingस्क्रॉल जब उपयोगकर्ता छोर खींच:

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

हम एक स्प्रिंग एनीमेशन का उपयोग कर सकते हैं और मोशन फ्लो को बेहतर बनाने के लिए एनिमेशन करते हुए उपयोगकर्ता इंटरैक्शन की अनुमति दे सकते हैं:

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

एनीमेशन चरणों के दौरान यह दृष्टिकोण इंटरैक्टिव नहीं है। उदाहरण के लिए, मैप्स में, मैं अपनी उंगली से शीट को पकड़ सकता हूं क्योंकि यह विस्तार कर रहा है। मैं ऊपर या नीचे पैन करके एनीमेशन को स्क्रब कर सकता हूं। जो भी निकटतम होगा, वह वापस आ जाएगा। मेरा मानना ​​है कि इसका उपयोग करके हल किया जा सकता है UIViewPropertyAnimator(जिसमें रोकने की क्षमता है), फिर fractionCompleteस्क्रब करने के लिए संपत्ति का उपयोग करें ।
प्रातः

1
आप ठीक कह रहे हैं @aust। मैं अपने पिछले बदलाव को आगे बढ़ाना भूल गया। यह अब अच्छा होना चाहिए। धन्यवाद।
GaétanZ

यह एक महान विचार है, हालांकि मैं अभी एक समस्या देख सकता हूं। जिस translateView(following:)विधि में आप अनुवाद के आधार पर ऊँचाई की गणना करते हैं, लेकिन वह 0.0 से भिन्न मान से शुरू हो सकती है (जैसे तालिका दृश्य थोड़ा स्क्रॉल किया जाता है और जब आप खींचना शुरू करते हैं तो ओवरले को अधिकतम किया जाता है) । इसका परिणाम यह होगा कि शुरुआती छलांग लगाई जाएगी। आप इसे scrollViewWillBeginDraggingकॉलबैक द्वारा हल कर सकते हैं, जहां आपको contentOffsetतालिका के प्रारंभिक दृश्य याद होंगे और इसका उपयोग translateView(following:)गणना में है।
जैकब ट्रूहला

1
@ GaétanZ I का रूचि थी कि वे मैप्सएप पर डेब्यूगर को सिम्युलेटर में भी शामिल करना चाहते हैं, लेकिन एक त्रुटि मिलती है "पिड में संलग्न नहीं हो सकते:" 9276 "" के साथ "सुनिश्चित करें" मैप्स पहले से ही नहीं चल रहा है, और इस उपयोगकर्ता नाम की अनुमति है इसे डिबग करें। " - आपने मैपकोड को संलग्न करने की अनुमति देने के लिए एक्सकोड को कैसे धोखा दिया?
मैट

1
@matm @ GaéanZZ ने मेरे लिए Xcode 10.1 / Mojave पर काम किया -> सिस्टम इंटीग्रिटी प्रोटेक्शन (SIP) को निष्क्रिय करने के लिए बस निष्क्रिय करने की आवश्यकता है। आपको निम्न करने की आवश्यकता है: 1) अपने मैक को पुनरारंभ करें; 2) सीएमडी + आर को दबाए रखें; 3) मेनू से यूटिलिटीज फिर टर्मिनल का चयन करें; 4) टर्मिनल विंडो प्रकार में csrutil disable && reboot:। फिर आपके पास सभी शक्तियां होंगी जो रूट को आम तौर पर आपको एक Apple प्रक्रिया से जुड़ने में सक्षम होने सहित देना चाहिए।
14

18

चरखी की कोशिश करें :

पुली आईओएस 10 के मैप्स ऐप में दराज की नकल करने के लिए उपयोग किए जाने वाले ड्रॉअर लाइब्रेरी का उपयोग करना आसान है। यह एक साधारण एपीआई को उजागर करता है जो आपको ड्रावर कंटेंट या प्राथमिक सामग्री के रूप में किसी भी यूआईवीवाईकंट्रोलर उपवर्ग का उपयोग करने की अनुमति देता है।

चरखी पूर्वावलोकन

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


1
क्या यह अंतर्निहित सूची में स्क्रॉलिंग का समर्थन करता है?
रिचर्ड लिन्थआउट

@RichardLindhout - डेमो चलाने के बाद ऐसा लगता है कि यह स्क्रॉलिंग का समर्थन करता है, लेकिन ड्रॉअर को स्थानांतरित करने से लेकर सूची को स्क्रॉल करने तक के चिकनी संक्रमण का नहीं।
स्टॉफ

उदाहरण बाईं ओर के निचले हिस्से में Apple कानूनी लिंक को छिपाने के लिए प्रकट होता है।
गर्ड कास्टान

1
सुपर सरल प्रश्न, आपको नीचे की शीट के शीर्ष पर संकेतक कैसे मिला?
एक इस्प्रिल

12

आप मेरा जवाब https://github.com/SCENEE/FloatingPanel पर आज़मा सकते हैं । यह एक "निचला पत्रक" इंटरफ़ेस प्रदर्शित करने के लिए एक कंटेनर दृश्य नियंत्रक प्रदान करता है।

इसका उपयोग करना आसान है और आपको किसी भी जेस्चर पहचानकर्ता को संभालने में कोई आपत्ति नहीं है! इसके अलावा, यदि आवश्यक हो तो आप नीचे की शीट में स्क्रॉल दृश्य (या भाई के दृश्य) को ट्रैक कर सकते हैं।

यह एक सरल उदाहरण है। कृपया ध्यान दें कि आपको अपनी सामग्री को नीचे की शीट में प्रदर्शित करने के लिए एक दृश्य नियंत्रक तैयार करने की आवश्यकता है।

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

यहाँ एप्पल मैप्स की तरह एक स्थान खोज करने के लिए एक नीचे पत्रक को प्रदर्शित करने एक और उदाहरण कोड है।

सैंपल ऐप जैसे ऐप्पल मैप्स


fpc.set (contentViewController: newsVC), पुस्तकालय में विधि गायब
फारिस मुहम्मद

1
सुपर सरल प्रश्न, आपको नीचे की शीट के शीर्ष पर संकेतक कैसे मिला?
एक इस्प्रिल

1
@AIsrafil मुझे लगता है कि यह सिर्फ एक UIView है
ShadeToD

मुझे लगता है कि यह वास्तव में अच्छा समाधान है, लेकिन इस फ्लोटिंग पैनल के साथ मोडल व्यू कंट्रोलर पेश करने के साथ iOS 13 में एक समस्या है।
ShadeToD

11

Ios मैप्स ऐप में इच्छित व्यवहार को प्राप्त करने के लिए मैंने अपनी खुद की लाइब्रेरी लिखी। यह एक प्रोटोकॉल उन्मुख समाधान है। इसलिए आपको शीट कंट्रोलर बनाने के बजाय किसी बेस क्लास को इनहेरिट करने की ज़रूरत नहीं है और अपनी इच्छानुसार कॉन्फ़िगर करें। यह UINavigationController के साथ या बिना आंतरिक नेविगेशन / प्रस्तुति का भी समर्थन करता है।

अधिक जानकारी के लिए नीचे दिए गए लिंक देखें।

https://github.com/OfTheWolf/UBottomSheet

ubottom शीट


यह चयनित उत्तर होना चाहिए, क्योंकि आप अभी भी पॉपअप के पीछे वीसी पर क्लिक कर सकते हैं।
Jay

सुपर सरल प्रश्न, आपको नीचे की शीट के शीर्ष पर संकेतक कैसे मिला?
एक इस्प्रिल

1

मैंने हाल ही में एक घटक बनाया , जिसे SwipeableViewउपखंड कहा जाता है UIView, जो स्विफ्ट 5.1 में लिखा गया है। यह सभी 4 दिशाओं का समर्थन करता है, इसमें कई अनुकूलन विकल्प हैं और विभिन्न विशेषताओं और वस्तुओं को चेतन और प्रक्षेपित कर सकते हैं (जैसे कि लेआउट की कमी, पृष्ठभूमि / रंग, affine रूपांतरण, अल्फा चैनल और दृश्य केंद्र, इन सभी को संबंधित शो केस के साथ प्रदर्शित किया गया है)। यदि सेट या ऑटो का पता चला है तो यह आंतरिक स्क्रॉल दृश्य के साथ स्वाइप समन्वय का भी समर्थन करता है। उपयोग करने के लिए बहुत आसान और सरल होना चाहिए (मुझे आशा है कि straight)

Https://github.com/LucaIaco/SwipeableView पर लिंक करें

अवधारणा के सुबूत:

यहां छवि विवरण दर्ज करें

आशा करता हूँ की ये काम करेगा


0

हो सकता है कि आप मेरा जवाब https://github.com/AnYuan/AYPannel , पुली से प्रेरित होकर आजमा सकें । सूची को स्क्रॉल करने के लिए दराज को स्थानांतरित करने से चिकना संक्रमण। मैंने कंटेनर स्क्रॉल दृश्य पर एक पैन जेस्चर जोड़ा, और YES को वापस करने के लिए shouldRecognizeSimultantlyWithGestureRecognizer सेट करें। ऊपर मेरे गितुब लिंक में और अधिक विस्तार। मदद करना चाहते हैं।


6
हालांकि यह लिंक प्रश्न का उत्तर दे सकता है, लेकिन उत्तर के आवश्यक भागों को शामिल करना और संदर्भ के लिए लिंक प्रदान करना बेहतर है। लिंक-केवल उत्तर अमान्य हो सकते हैं यदि लिंक किए गए पृष्ठ बदल जाते हैं। हालांकि यह लिंक प्रश्न का उत्तर दे सकता है, लेकिन उत्तर के आवश्यक भागों को शामिल करना और संदर्भ के लिए लिंक प्रदान करना बेहतर है। लिंक-केवल उत्तर अमान्य हो सकते हैं यदि लिंक किए गए पृष्ठ बदल जाते हैं।
पिरहो
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.