ইউজিকলিকেশনভিউটি পর্দা নয় কক্ষগুলি দ্বারা পর্যালোচনা করুন


112

আমার UICollectionViewঅনুভূমিক স্ক্রোলিং রয়েছে এবং পুরো স্ক্রিনে সর্বদা 2 টি ঘর পাশাপাশি থাকে। ঘরের শুরুতে স্ক্রোলিংটি থামাতে আমার দরকার। পেজিং সক্ষম করা সহ, সংগ্রহ ভিউ পুরো পৃষ্ঠাটি স্ক্রোল করে, যা একবারে 2 টি ঘর এবং তারপরে এটি বন্ধ হয়ে যায়।

আমাকে একটি একক কক্ষ দ্বারা স্ক্রোলিং সক্ষম করতে হবে বা ঘরের প্রান্তে থামার সাথে একাধিক কক্ষ দ্বারা স্ক্রোলিং করতে হবে।

আমি সাবক্লাস UICollectionViewFlowLayoutএবং পদ্ধতিটি বাস্তবায়নের চেষ্টা করেছি targetContentOffsetForProposedContentOffset, তবে এখনও পর্যন্ত আমি কেবল আমার সংগ্রহের দৃশ্যটি ভেঙে ফেলতে সক্ষম হয়েছি এবং এটি স্ক্রোলিং বন্ধ করে দিয়েছে stopped এটি অর্জন করার কোনও সহজ উপায় আছে এবং কীভাবে, বা UICollectionViewFlowLayoutসাবক্লাসের সমস্ত পদ্ধতি বাস্তবায়িত করার দরকার আছে ? ধন্যবাদ।


1
আপনার কালেকশনভিউসেল প্রস্থ অবশ্যই স্ক্রেন প্রস্থ এবং সংগ্রহের সমান হবেভিউ পেজিং সক্ষম হয়েছে
এরহান

তবে আমাকে একবারে 2 টি সেল দেখানো দরকার। আমি আইপ্যাডে আছি, সুতরাং 2 টি সেল প্রতিটি পর্দার অর্ধেক ভাগ করে।
মার্টিন কোলস 14

2
targetContentOffsetForProposedContentOffset:withScrollingVelocity:পেজিং ব্যবহার করুন এবং বন্ধ করুন
ওয়াইন

এই আমি চেষ্টা করছি। কোথাও কোন উদাহরণ?
মার্টিন কোলস 14

উত্তর:


47

ঠিক আছে, সুতরাং আমি সমাধানটি এখানে পেয়েছি: টার্গেটকন্টেন্টএফসেটের জন্য প্রপোজড কনটেন্টঅফসেট: ইউআইকোলিকেশনভিউফ্লোলয়আউট সাবক্লাসিং ছাড়াই স্ক্রোলিংভেলসিটি

targetContentOffsetForProposedContentOffsetভিক্ষা করার সময় আমার সন্ধান করা উচিত ছিল ।


1
যে কেউ এই সম্পর্কে সুইফট 5-এ জিজ্ঞাসা করছে: সংগ্রহ ভিউ.আইসপেজিংএনেবলড = সত্য এটি করে!
মোহাম্মদ বশির সিদানি

23

কেবল পদ্ধতিটি ওভাররাইড করুন:

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
    *targetContentOffset = scrollView.contentOffset; // set acceleration to 0.0
    float pageWidth = (float)self.articlesCollectionView.bounds.size.width;
    int minSpace = 10;

    int cellToSwipe = (scrollView.contentOffset.x)/(pageWidth + minSpace) + 0.5; // cell width + min spacing for lines
    if (cellToSwipe < 0) {
        cellToSwipe = 0;
    } else if (cellToSwipe >= self.articles.count) {
        cellToSwipe = self.articles.count - 1;
    }
    [self.articlesCollectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:cellToSwipe inSection:0] atScrollPosition:UICollectionViewScrollPositionLeft animated:YES];
}

1
কোডটির এই অংশটি আমাকে অনেক সাহায্য করেছিল, আমাকে বর্তমান স্ক্রোলিং দিকের জন্য চেকটি যুক্ত করতে হয়েছিল এবং ততক্ষণে +/- 0.5 মানটি অভিযোজিত হয়েছিল।
হেলকারলি


@ ইভ্যা ওয়া আপনি ঠিক বলেছেন #PageEn सक्षम আমার জন্য কাজ করেছে।
বিগসস

@ এভায়া দুর্দান্ত জিনিস !!
আনিস কুমার

কীভাবে আপনার ছেলেরা জন্য প্যাজিংএইনেবল কাজ করছে? অরিজিনাল পেজিং অফসেটে শেষ হওয়ার আগে খনি সুপার গ্ল্যাচি পেয়েছে
ইথান ঝাও

17

কাস্টম পৃষ্ঠার প্রস্থ সহ অনুভূমিক পেজিং (সুইফট 4 এবং 5)

এখানে উপস্থাপিত অনেকগুলি সমাধানের ফলে কিছু অদ্ভুত আচরণ দেখা যায় যা সঠিকভাবে প্রয়োগ করা পেজিংয়ের মতো মনে হয় না।


এই টিউটোরিয়ালে উপস্থাপন করা সমাধানের কোনও সমস্যা আছে বলে মনে হয় না। এটি ঠিক নিখুঁতভাবে কাজ করার পেজিং অ্যালগরিদমের মতো অনুভব করে। আপনি এটি 5 টি সাধারণ পদক্ষেপে প্রয়োগ করতে পারেন:

  1. আপনার ধরণে নিম্নলিখিত সম্পত্তি যুক্ত করুন: private var indexOfCellBeforeDragging = 0
  2. এই collectionView delegateমত সেট করুন :collectionView.delegate = self
  3. UICollectionViewDelegateএকটি এক্সটেনশনের মাধ্যমে কনফারেন্স যুক্ত করুন :extension YourType: UICollectionViewDelegate { }
  4. UICollectionViewDelegateকনফরমেশন বাস্তবায়ন করে এক্সটেনশনে নিম্নলিখিত পদ্ধতিটি যুক্ত করুন এবং এর জন্য একটি মান সেট করুন pageWidth:

    func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
        let pageWidth = // The width your page should have (plus a possible margin)
        let proportionalOffset = collectionView.contentOffset.x / pageWidth
        indexOfCellBeforeDragging = Int(round(proportionalOffset))
    }
  5. UICollectionViewDelegateকনফরমেশন বাস্তবায়ন করতে এক্সটেনশনে নিম্নলিখিত পদ্ধতিটি যুক্ত করুন , এর জন্য একই মান নির্ধারণ করুন pageWidth(আপনি এই মানটি কোনও কেন্দ্রীয় স্থানেও সঞ্চয় করতে পারেন) এবং এর জন্য একটি মান সেট করুন collectionViewItemCount:

    func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
        // Stop scrolling
        targetContentOffset.pointee = scrollView.contentOffset
    
        // Calculate conditions
        let pageWidth = // The width your page should have (plus a possible margin)
        let collectionViewItemCount = // The number of items in this section
        let proportionalOffset = collectionView.contentOffset.x / pageWidth
        let indexOfMajorCell = Int(round(proportionalOffset))
        let swipeVelocityThreshold: CGFloat = 0.5
        let hasEnoughVelocityToSlideToTheNextCell = indexOfCellBeforeDragging + 1 < collectionViewItemCount && velocity.x > swipeVelocityThreshold
        let hasEnoughVelocityToSlideToThePreviousCell = indexOfCellBeforeDragging - 1 >= 0 && velocity.x < -swipeVelocityThreshold
        let majorCellIsTheCellBeforeDragging = indexOfMajorCell == indexOfCellBeforeDragging
        let didUseSwipeToSkipCell = majorCellIsTheCellBeforeDragging && (hasEnoughVelocityToSlideToTheNextCell || hasEnoughVelocityToSlideToThePreviousCell)
    
        if didUseSwipeToSkipCell {
            // Animate so that swipe is just continued
            let snapToIndex = indexOfCellBeforeDragging + (hasEnoughVelocityToSlideToTheNextCell ? 1 : -1)
            let toValue = pageWidth * CGFloat(snapToIndex)
            UIView.animate(
                withDuration: 0.3,
                delay: 0,
                usingSpringWithDamping: 1,
                initialSpringVelocity: velocity.x,
                options: .allowUserInteraction,
                animations: {
                    scrollView.contentOffset = CGPoint(x: toValue, y: 0)
                    scrollView.layoutIfNeeded()
                },
                completion: nil
            )
        } else {
            // Pop back (against velocity)
            let indexPath = IndexPath(row: indexOfMajorCell, section: 0)
            collectionView.scrollToItem(at: indexPath, at: .left, animated: true)
        }
    }

এই ব্যবহার করে কারো জন্য আপনি পরিবর্তন করতে হবে Pop back (against velocity)অংশ হতে: collectionViewLayout.collectionView!.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)। দ্রষ্টব্য.centeredHorizontally
ম্যাথিউ.ক্যাম্পসন

আপনি কীভাবে লেআউটটি আচরণ করতে চান তার উপর নির্ভর করে @ ম্যাথিউ.কেম্পসন। এই লেআউটটির জন্য আমি এটি ব্যবহার করেছি, ভাল .leftছিল
ফ্রেডপি

আমি খুঁজে পেয়েছি যে .leftপ্রত্যাশা মত কাজ করে না। এটি সেলটিকে অনেক পিছনে ঠেলে দেবে বলে মনে হয়েছিল @ ফ্রেডপি
ম্যাথজ.ক্যাম্পসন

13

এভিয়ার উত্তরের সুইফ্ট 3 সংস্করণ:

func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
  targetContentOffset.pointee = scrollView.contentOffset
    let pageWidth:Float = Float(self.view.bounds.width)
    let minSpace:Float = 10.0
    var cellToSwipe:Double = Double(Float((scrollView.contentOffset.x))/Float((pageWidth+minSpace))) + Double(0.5)
    if cellToSwipe < 0 {
        cellToSwipe = 0
    } else if cellToSwipe >= Double(self.articles.count) {
        cellToSwipe = Double(self.articles.count) - Double(1)
    }
    let indexPath:IndexPath = IndexPath(row: Int(cellToSwipe), section:0)
    self.collectionView.scrollToItem(at:indexPath, at: UICollectionViewScrollPosition.left, animated: true)


}

আপনি যখন ঘরের পাশে ক্লিক করেন, সেখানে একটি অদ্ভুত অফসেট থাকে
মাওর

আরে @ মওর, আপনার এখনও এটির দরকার আছে কিনা আমি জানি না তবে আমার ক্ষেত্রে এটি সংগ্রহের দৃশ্যে পেজিং অক্ষম করা ঠিক হয়েছিল।
ফার্নান্দো মাটা

2
আমি এটি পছন্দ করেছিলাম তবে দ্রুত ছোট ছোট সোয়াইপগুলি নিয়ে কিছুটা আলগা মনে হয়েছিল, তাই আমি বেগটিকে অ্যাকাউন্টে নিতে কিছু যুক্ত করেছি এবং এটিকে আরও মসৃণ করে তোলে: if(velocity.x > 1) { mod = 0.5; } else if(velocity.x < -1) { mod = -0.5; }তারপরে যুক্ত করুন+ mod করে + Double(0.5)
তুলি

12

হোরাইঞ্জোনাল স্ক্রোলের জন্য সুইফট ৪.২- এ আমি এটি করতে সবচেয়ে সহজ উপায়টি এখানে পেয়েছি :

আমি প্রথম সেলটি ব্যবহার করছি visibleCellsএবং তারপরে স্ক্রোল করছি, যদি প্রথম দৃশ্যমান ঘরটি এর প্রস্থের অর্ধেকের কম দেখায় আমি পরেরটিতে স্ক্রোল করছি।

যদি আপনার সংগ্রহটি উল্লম্বভাবে স্ক্রোল করে , সহজভাবে পরিবর্তন xদ্বারা yএবং widthদ্বারাheight

func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
    targetContentOffset.pointee = scrollView.contentOffset
    var indexes = self.collectionView.indexPathsForVisibleItems
    indexes.sort()
    var index = indexes.first!
    let cell = self.collectionView.cellForItem(at: index)!
    let position = self.collectionView.contentOffset.x - cell.frame.origin.x
    if position > cell.frame.size.width/2{
       index.row = index.row+1
    }
    self.collectionView.scrollToItem(at: index, at: .left, animated: true )
}

আপনি কি দয়া করে উত্স নিবন্ধটিতে লিঙ্কটি যুক্ত করতে পারেন। দুর্দান্ত উত্তর বিটিডাব্লু।
মোঃ ইব্রাহিম হাসান

@ মোঃ ইব্রাহিমহসান কোন নিবন্ধ নেই, আমিই এর উত্স। থেক্স
রোমুলো বিএম

এটি কাজ করে, তবে দুর্ভাগ্যক্রমে অভিজ্ঞতাটি মসৃণ নয়
আলা এডিন চেরবিব

আপনি মসৃণ না দিয়ে কি বোঝাতে চান? আমার জন্য, ফলাফলটি খুব মসৃণভাবে অ্যানিমেটেড .. আমার ফলাফলটি এখানে দেখুন
রোমুলো বিএম

এটি দুর্দান্ত কাজ করে
অনুজ কুমার রাই Rai

9

আংশিকভাবে স্টিভেনজোর উত্তরের ভিত্তিতে। আমি এটি একটি অনুভূমিক স্ক্রোলিং এবং কোনও বাউন্স ইউআইসোলিকেশনভিউ ব্যবহার করে পরীক্ষা করেছি। সেলসাইজ হ'ল কালেকশনভিউসেল আকার। স্ক্রোলিং সংবেদনশীলতা সংশোধন করতে আপনি ফ্যাক্টর টিচ করতে পারেন।

override func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
    targetContentOffset.pointee = scrollView.contentOffset
    var factor: CGFloat = 0.5
    if velocity.x < 0 {
        factor = -factor
    }
    let indexPath = IndexPath(row: (scrollView.contentOffset.x/cellSize.width + factor).int, section: 0)
    collectionView?.scrollToItem(at: indexPath, at: .left, animated: true)
}

9

উল্লম্ব সেল-ভিত্তিক পেজিংয়ের জন্য সুইফট 5 এ আমার বাস্তবায়ন এখানে রয়েছে :

override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {

    guard let collectionView = self.collectionView else {
        let latestOffset = super.targetContentOffset(forProposedContentOffset: proposedContentOffset, withScrollingVelocity: velocity)
        return latestOffset
    }

    // Page height used for estimating and calculating paging.
    let pageHeight = self.itemSize.height + self.minimumLineSpacing

    // Make an estimation of the current page position.
    let approximatePage = collectionView.contentOffset.y/pageHeight

    // Determine the current page based on velocity.
    let currentPage = velocity.y == 0 ? round(approximatePage) : (velocity.y < 0.0 ? floor(approximatePage) : ceil(approximatePage))

    // Create custom flickVelocity.
    let flickVelocity = velocity.y * 0.3

    // Check how many pages the user flicked, if <= 1 then flickedPages should return 0.
    let flickedPages = (abs(round(flickVelocity)) <= 1) ? 0 : round(flickVelocity)

    let newVerticalOffset = ((currentPage + flickedPages) * pageHeight) - collectionView.contentInset.top

    return CGPoint(x: proposedContentOffset.x, y: newVerticalOffset)
}

কিছু নোট:

  • ভুল নেই
  • মিথ্যাতে প্যাগিং সেট করুন ! (অন্যথায় এটি কাজ করবে না)
  • আপনাকে সহজেই নিজের ফ্লিকবেলসিটি সেট করতে দেয় ।
  • এটি চেষ্টা করার পরেও যদি কিছু কাজ না করে থাকে তবে আপনার itemSizeআইটেমটির আকারটি আসলে মিলছে কিনা তা যাচাই করে দেখুন, বিশেষত collectionView(_:layout:sizeForItemAt:)ব্যবহারের সময় আইটেম সাইজের পরিবর্তে কাস্টম ভেরিয়েবল ব্যবহার করুন।
  • আপনি সেট করার সময় এটি সবচেয়ে ভাল কাজ করে self.collectionView.decelerationRate = UIScrollView.DecelerationRate.fast

এখানে একটি অনুভূমিক সংস্করণ রয়েছে (এটির পুরোপুরি পরীক্ষা করা হয়নি তাই দয়া করে কোনও ভুল ক্ষমা করুন):

override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {

    guard let collectionView = self.collectionView else {
        let latestOffset = super.targetContentOffset(forProposedContentOffset: proposedContentOffset, withScrollingVelocity: velocity)
        return latestOffset
    }

    // Page width used for estimating and calculating paging.
    let pageWidth = self.itemSize.width + self.minimumInteritemSpacing

    // Make an estimation of the current page position.
    let approximatePage = collectionView.contentOffset.x/pageWidth

    // Determine the current page based on velocity.
    let currentPage = velocity.x == 0 ? round(approximatePage) : (velocity.x < 0.0 ? floor(approximatePage) : ceil(approximatePage))

    // Create custom flickVelocity.
    let flickVelocity = velocity.x * 0.3

    // Check how many pages the user flicked, if <= 1 then flickedPages should return 0.
    let flickedPages = (abs(round(flickVelocity)) <= 1) ? 0 : round(flickVelocity)

    // Calculate newHorizontalOffset.
    let newHorizontalOffset = ((currentPage + flickedPages) * pageWidth) - collectionView.contentInset.left

    return CGPoint(x: newHorizontalOffset, y: proposedContentOffset.y)
}

এই কোডটি আমি আমার ব্যক্তিগত প্রকল্পে যে কোডটি ব্যবহার করি তার উপর ভিত্তি করে, আপনি এটি ডাউনলোড করে এবং উদাহরণ টার্গেট চালিয়ে এখানে এটি পরীক্ষা করে দেখতে পারেন ।


1
সুইফ্ট 5 এর জন্য: এর .fastপরিবর্তে ব্যবহার করুনUIScollViewDecelerationRateFast
জোসে

যে ইশারা জন্য ধন্যবাদ! এই উত্তরটি আপডেট করতে ভুলে গেছেন এবং স্রেফ করেছেন!
JoniVR

হাই, @ জনিভিআর কীভাবে সোয়াইপিংটি উল্লম্বভাবে কাজ করবে তা দেখানোর জন্য খুব সুন্দর ব্যাখ্যা উদাহরণ। একটি অনুভূমিক দিক নির্বিঘ্নে এই কাজটি করার জন্য সামগ্রিক কোড পরিবর্তনের জন্য আপনাকে কী পরামর্শ দেওয়া উচিত তা আপনার জন্য অত্যন্ত ধরণের হবে। উপরের কোড ব্যতীত আপনি লক্ষ্যবস্তু অফসেট ফাংশনে অনুভূমিক সোয়াইপ করার পরামর্শ দিয়েছেন। আমি মনে করি সঠিক দৃশ্যটিকে অনুভূমিকভাবে প্রতিলিপি করতে অনেক পরিবর্তন হয়েছে। আমি ভুল হলে আমাকে সংশোধন করুন।
শিব প্রকাশ

7

পদ্ধতির 1: সংগ্রহ দেখুন View

flowLayout হয় UICollectionViewFlowLayout সম্পত্তি

override func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {

    if let collectionView = collectionView {

        targetContentOffset.memory = scrollView.contentOffset
        let pageWidth = CGRectGetWidth(scrollView.frame) + flowLayout.minimumInteritemSpacing

        var assistanceOffset : CGFloat = pageWidth / 3.0

        if velocity.x < 0 {
            assistanceOffset = -assistanceOffset
        }

        let assistedScrollPosition = (scrollView.contentOffset.x + assistanceOffset) / pageWidth

        var targetIndex = Int(round(assistedScrollPosition))


        if targetIndex < 0 {
            targetIndex = 0
        }
        else if targetIndex >= collectionView.numberOfItemsInSection(0) {
            targetIndex = collectionView.numberOfItemsInSection(0) - 1
        }

        print("targetIndex = \(targetIndex)")

        let indexPath = NSIndexPath(forItem: targetIndex, inSection: 0)

        collectionView.scrollToItemAtIndexPath(indexPath, atScrollPosition: .Left, animated: true)
    }
}

পদ্ধতির 2: পৃষ্ঠা দেখুন নিয়ন্ত্রক

UIPageViewControllerএটি আপনার প্রয়োজনীয়তা পূরণ করে যদি আপনি ব্যবহার করতে পারেন , প্রতিটি পৃষ্ঠায় একটি পৃথক দর্শন নিয়ামক থাকবে।


এর জন্য আমাকে কেবল প্লেজিংভিউতে পেজিং অক্ষম করতে হবে এবং স্ক্রোলিং সক্ষম করতে হবে?
এনআর 5

এটি সর্বশেষতম swift4 / Xcode9.3 এর জন্য কাজ করছে না, টার্গেটকন্টেন্ট অফসটির কোনও মেমরি ক্ষেত্র নেই। আমি স্ক্রোলিং প্রয়োগ করেছি কিন্তু আপনি "ঝাঁকুনি" দেওয়ার সময় এটি সেল অবস্থানটি সামঞ্জস্য করে না।
স্টিভেন বি

কয়েকটি কক্ষের সাথে কাজ করে তবে আমি যখন ১৩ এ সেল এ পৌঁছায় এটি পূর্বের ঘরে ফিরে আসতে শুরু করে এবং আপনি চালিয়ে যেতে পারবেন না।
ক্রিস্টোফার স্মিট

4

এটি করার জন্য এটি একটি সরল উপায়।

কেসটি সহজ তবে অবশেষে বেশ সাধারণ (নির্দিষ্ট কক্ষের আকার এবং কোষের মধ্যে স্থির ব্যবধান সহ সাধারণ থাম্বনেইস স্ক্রোলার)

var itemCellSize: CGSize = <your cell size>
var itemCellsGap: CGFloat = <gap in between>

override func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
    let pageWidth = (itemCellSize.width + itemCellsGap)
    let itemIndex = (targetContentOffset.pointee.x) / pageWidth
    targetContentOffset.pointee.x = round(itemIndex) * pageWidth - (itemCellsGap / 2)
}

// CollectionViewFlowLayoutDelegate

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    return itemCellSize
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
    return itemCellsGap
}

মনে রাখবেন যে কোনও স্ক্রোলটোফসেট কল করার বা লেআউটে ডুব দেওয়ার কোনও কারণ নেই। নেটিভ স্ক্রোলিং আচরণ ইতিমধ্যে সমস্ত কিছু করে।

চিয়ার্স সব :)


2
আপনি collectionView.decelerationRate = .fastallyচ্ছিকভাবে মিমমিক ডিফল্ট পেজিংয়ের নিকটে সেট করতে পারেন ।
এলফানেক

1
এটি সত্যিই দুর্দান্ত। @ বেলনেক আমি খুঁজে পেয়েছি যে সেটিংটি ঠিকঠাক কাজ করে যদি আপনি একটি ছোট এবং মৃদু সোয়াইপ না করেন তবে এটি কেবল ঝাঁকুনির মতো মনে হচ্ছে।
mylogon

3

ইভিয়ার উত্তরটির মতো, তবে এটি কিছুটা মসৃণ কারণ এটি টার্গেটকন্টেন্ট অফসেটকে শূন্যে সেট করে না।

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
    if ([scrollView isKindOfClass:[UICollectionView class]]) {
        UICollectionView* collectionView = (UICollectionView*)scrollView;
        if ([collectionView.collectionViewLayout isKindOfClass:[UICollectionViewFlowLayout class]]) {
            UICollectionViewFlowLayout* layout = (UICollectionViewFlowLayout*)collectionView.collectionViewLayout;

            CGFloat pageWidth = layout.itemSize.width + layout.minimumInteritemSpacing;
            CGFloat usualSideOverhang = (scrollView.bounds.size.width - pageWidth)/2.0;
            // k*pageWidth - usualSideOverhang = contentOffset for page at index k if k >= 1, 0 if k = 0
            // -> (contentOffset + usualSideOverhang)/pageWidth = k at page stops

            NSInteger targetPage = 0;
            CGFloat currentOffsetInPages = (scrollView.contentOffset.x + usualSideOverhang)/pageWidth;
            targetPage = velocity.x < 0 ? floor(currentOffsetInPages) : ceil(currentOffsetInPages);
            targetPage = MAX(0,MIN(self.projects.count - 1,targetPage));

            *targetContentOffset = CGPointMake(MAX(targetPage*pageWidth - usualSideOverhang,0), 0);
        }
    }
}

2

সুইফট 5

আমি ইউআইকোলিকেশনভিউ সাবক্লাসিং না করে এটি করার একটি উপায় খুঁজে পেয়েছি, কেবল অনুভূমিকভাবে অফসেটের অফসেট গণনা করছি। স্পষ্টতই isPasingEn सक्षम সেট ছাড়া সত্য। কোডটি এখানে:

var offsetScroll1 : CGFloat = 0
var offsetScroll2 : CGFloat = 0
let flowLayout = UICollectionViewFlowLayout()
let screenSize : CGSize = UIScreen.main.bounds.size
var items = ["1", "2", "3", "4", "5"]

override func viewDidLoad() {
    super.viewDidLoad()
    flowLayout.scrollDirection = .horizontal
    flowLayout.minimumLineSpacing = 7
    let collectionView = UICollectionView(frame: CGRect(x: 0, y: 590, width: screenSize.width, height: 200), collectionViewLayout: flowLayout)
    collectionView.register(collectionViewCell1.self, forCellWithReuseIdentifier: cellReuseIdentifier)
    collectionView.delegate = self
    collectionView.dataSource = self
    collectionView.backgroundColor = UIColor.clear
    collectionView.showsHorizontalScrollIndicator = false
    self.view.addSubview(collectionView)
}

func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
    offsetScroll1 = offsetScroll2
}

func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
    offsetScroll1 = offsetScroll2
}

func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>){
    let indexOfMajorCell = self.desiredIndex()
    let indexPath = IndexPath(row: indexOfMajorCell, section: 0)
    flowLayout.collectionView!.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
    targetContentOffset.pointee = scrollView.contentOffset
}

private func desiredIndex() -> Int {
    var integerIndex = 0
    print(flowLayout.collectionView!.contentOffset.x)
    offsetScroll2 = flowLayout.collectionView!.contentOffset.x
    if offsetScroll2 > offsetScroll1 {
        integerIndex += 1
        let offset = flowLayout.collectionView!.contentOffset.x / screenSize.width
        integerIndex = Int(round(offset))
        if integerIndex < (items.count - 1) {
            integerIndex += 1
        }
    }
    if offsetScroll2 < offsetScroll1 {
        let offset = flowLayout.collectionView!.contentOffset.x / screenSize.width
        integerIndex = Int(offset.rounded(.towardZero))
    }
    let targetIndex = integerIndex
    return targetIndex
}

1

এখানে এটির আমার সংস্করণটি সুইফট 3 এ রয়েছে স্ক্রোলিং শেষ হওয়ার পরে অফসেটটি গণনা করুন এবং অ্যানিমেশন সহ অফসেটটি সামঞ্জস্য করুন।

collectionLayout ইহা একটি UICollectionViewFlowLayout()

func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
    let index = scrollView.contentOffset.x / collectionLayout.itemSize.width
    let fracPart = index.truncatingRemainder(dividingBy: 1)
    let item= Int(fracPart >= 0.5 ? ceil(index) : floor(index))

    let indexPath = IndexPath(item: item, section: 0)
    collectionView.scrollToItem(at: indexPath, at: .left, animated: true)
}

1

এছাড়াও আপনি স্ক্রোলিং পরিচালনা করতে নকল স্ক্রোল ভিউ তৈরি করতে পারেন।

অনুভূমিক বা উল্লম্ব

// === Defaults ===
let bannerSize = CGSize(width: 280, height: 170)
let pageWidth: CGFloat = 290 // ^ + paging
let insetLeft: CGFloat = 20
let insetRight: CGFloat = 20
// ================

var pageScrollView: UIScrollView!

override func viewDidLoad() {
    super.viewDidLoad()

    // Create fake scrollview to properly handle paging
    pageScrollView = UIScrollView(frame: CGRect(origin: .zero, size: CGSize(width: pageWidth, height: 100)))
    pageScrollView.isPagingEnabled = true
    pageScrollView.alwaysBounceHorizontal = true
    pageScrollView.showsVerticalScrollIndicator = false
    pageScrollView.showsHorizontalScrollIndicator = false
    pageScrollView.delegate = self
    pageScrollView.isHidden = true
    view.insertSubview(pageScrollView, belowSubview: collectionView)

    // Set desired gesture recognizers to the collection view
    for gr in pageScrollView.gestureRecognizers! {
        collectionView.addGestureRecognizer(gr)
    }
}

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    if scrollView == pageScrollView {
        // Return scrolling back to the collection view
        collectionView.contentOffset.x = pageScrollView.contentOffset.x
    }
}

func refreshData() {
    ...

    refreshScroll()
}

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    refreshScroll()
}

/// Refresh fake scrolling view content size if content changes
func refreshScroll() {
    let w = collectionView.width - bannerSize.width - insetLeft - insetRight
    pageScrollView.contentSize = CGSize(width: pageWidth * CGFloat(banners.count) - w, height: 100)
}

1

বেগ শোনার জন্য রোমুলো বিএম উত্তর সংশোধন করুন

func scrollViewWillEndDragging(
    _ scrollView: UIScrollView,
    withVelocity velocity: CGPoint,
    targetContentOffset: UnsafeMutablePointer<CGPoint>
) {
    targetContentOffset.pointee = scrollView.contentOffset
    var indexes = collection.indexPathsForVisibleItems
    indexes.sort()
    var index = indexes.first!
    if velocity.x > 0 {
       index.row += 1
    } else if velocity.x == 0 {
        let cell = self.collection.cellForItem(at: index)!
        let position = self.collection.contentOffset.x - cell.frame.origin.x
        if position > cell.frame.size.width / 2 {
           index.row += 1
        }
    }

    self.collection.scrollToItem(at: index, at: .centeredHorizontally, animated: true )
}

0

ঠিক আছে সুতরাং প্রস্তাবিত উত্তরগুলি আমার পক্ষে কাজ করবে না কারণ আমি পরিবর্তে বিভাগগুলি দ্বারা স্ক্রোল করতে চেয়েছিলাম এবং এর ফলে ভেরিয়েবলের প্রস্থ পৃষ্ঠার আকার থাকতে পারে

আমি এটি করেছি (কেবল উল্লম্ব):

   var pagesSizes = [CGSize]()
   func scrollViewDidScroll(_ scrollView: UIScrollView) {
        defer {
            lastOffsetY = scrollView.contentOffset.y
        }
        if collectionView.isDecelerating {
            var currentPage = 0
            var currentPageBottom = CGFloat(0)
            for pagesSize in pagesSizes {
                currentPageBottom += pagesSize.height
                if currentPageBottom > collectionView!.contentOffset.y {
                    break
                }
                currentPage += 1
            }
            if collectionView.contentOffset.y > currentPageBottom - pagesSizes[currentPage].height, collectionView.contentOffset.y + collectionView.frame.height < currentPageBottom {
                return // 100% of view within bounds
            }
            if lastOffsetY < collectionView.contentOffset.y {
                if currentPage + 1 != pagesSizes.count {
                    collectionView.setContentOffset(CGPoint(x: 0, y: currentPageBottom), animated: true)
                }
            } else {
                collectionView.setContentOffset(CGPoint(x: 0, y: currentPageBottom - pagesSizes[currentPage].height), animated: true)
            }
        }
    }

এই ক্ষেত্রে, আমি বিভাগের উচ্চতা + শিরোনাম + পাদচরণ ব্যবহার করে আগেই প্রতিটি পৃষ্ঠার আকার গণনা করে অ্যারেতে সঞ্চয় করি। এটাই pagesSizesমেম্বার


0

এটি আমার সমাধান, সুইফট ৪.২-এ, আমি আশা করি এটি আপনাকে সহায়তা করতে পারে।

class SomeViewController: UIViewController {

  private lazy var flowLayout: UICollectionViewFlowLayout = {
    let layout = UICollectionViewFlowLayout()
    layout.itemSize = CGSize(width: /* width */, height: /* height */)
    layout.minimumLineSpacing = // margin
    layout.minimumInteritemSpacing = 0.0
    layout.sectionInset = UIEdgeInsets(top: 0.0, left: /* margin */, bottom: 0.0, right: /* margin */)
    layout.scrollDirection = .horizontal
    return layout
  }()

  private lazy var collectionView: UICollectionView = {
    let collectionView = UICollectionView(frame: .zero, collectionViewLayout: flowLayout)
    collectionView.showsHorizontalScrollIndicator = false
    collectionView.dataSource = self
    collectionView.delegate = self
    // collectionView.register(SomeCell.self)
    return collectionView
  }()

  private var currentIndex: Int = 0
}

// MARK: - UIScrollViewDelegate

extension SomeViewController {
  func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
    guard scrollView == collectionView else { return }

    let pageWidth = flowLayout.itemSize.width + flowLayout.minimumLineSpacing
    currentIndex = Int(scrollView.contentOffset.x / pageWidth)
  }

  func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
    guard scrollView == collectionView else { return }

    let pageWidth = flowLayout.itemSize.width + flowLayout.minimumLineSpacing
    var targetIndex = Int(roundf(Float(targetContentOffset.pointee.x / pageWidth)))
    if targetIndex > currentIndex {
      targetIndex = currentIndex + 1
    } else if targetIndex < currentIndex {
      targetIndex = currentIndex - 1
    }
    let count = collectionView.numberOfItems(inSection: 0)
    targetIndex = max(min(targetIndex, count - 1), 0)
    print("targetIndex: \(targetIndex)")

    targetContentOffset.pointee = scrollView.contentOffset
    var offsetX: CGFloat = 0.0
    if targetIndex < count - 1 {
      offsetX = pageWidth * CGFloat(targetIndex)
    } else {
      offsetX = scrollView.contentSize.width - scrollView.width
    }
    collectionView.setContentOffset(CGPoint(x: offsetX, y: 0.0), animated: true)
  }
}

0
final class PagingFlowLayout: UICollectionViewFlowLayout {
    private var currentIndex = 0

    override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
        let count = collectionView!.numberOfItems(inSection: 0)
        let currentAttribute = layoutAttributesForItem(
            at: IndexPath(item: currentIndex, section: 0)
            ) ?? UICollectionViewLayoutAttributes()

        let direction = proposedContentOffset.x > currentAttribute.frame.minX
        if collectionView!.contentOffset.x + collectionView!.bounds.width < collectionView!.contentSize.width || currentIndex < count - 1 {
            currentIndex += direction ? 1 : -1
            currentIndex = max(min(currentIndex, count - 1), 0)
        }

        let indexPath = IndexPath(item: currentIndex, section: 0)
        let closestAttribute = layoutAttributesForItem(at: indexPath) ?? UICollectionViewLayoutAttributes()

        let centerOffset = collectionView!.bounds.size.width / 2
        return CGPoint(x: closestAttribute.center.x - centerOffset, y: 0)
    }
}

আপনার উত্তরগুলি অনুলিপি / আটকানো উচিত নয়। উপযুক্ত হলে এটি সদৃশ হিসাবে চিহ্নিত করুন।
ডনম্যাগ

-1

UICollectionViewFlowLayoutওভাররাইড করতে একটি ব্যবহার করে এটি করার আমার উপায় এখানে targetContentOffset:

(যদিও শেষ পর্যন্ত, আমি এটি ব্যবহার না করে শেষ করে ইউআইপিএজভিউ কনট্রোলার ব্যবহার করব না))

/**
 A UICollectionViewFlowLayout with...
 - paged horizontal scrolling
 - itemSize is the same as the collectionView bounds.size
 */
class PagedFlowLayout: UICollectionViewFlowLayout {

  override init() {
    super.init()
    self.scrollDirection = .horizontal
    self.minimumLineSpacing = 8 // line spacing is the horizontal spacing in horizontal scrollDirection
    self.minimumInteritemSpacing = 0
    if #available(iOS 11.0, *) {
      self.sectionInsetReference = .fromSafeArea // for iPhone X
    }
  }

  required init?(coder aDecoder: NSCoder) {
    fatalError("not implemented")
  }

  // Note: Setting `minimumInteritemSpacing` here will be too late. Don't do it here.
  override func prepare() {
    super.prepare()
    guard let collectionView = collectionView else { return }
    collectionView.decelerationRate = UIScrollViewDecelerationRateFast // mostly you want it fast!

    let insetedBounds = UIEdgeInsetsInsetRect(collectionView.bounds, self.sectionInset)
    self.itemSize = insetedBounds.size
  }

  // Table: Possible cases of targetContentOffset calculation
  // -------------------------
  // start |          |
  // near  | velocity | end
  // page  |          | page
  // -------------------------
  //   0   | forward  |  1
  //   0   | still    |  0
  //   0   | backward |  0
  //   1   | forward  |  1
  //   1   | still    |  1
  //   1   | backward |  0
  // -------------------------
  override func targetContentOffset( //swiftlint:disable:this cyclomatic_complexity
    forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {

    guard let collectionView = collectionView else { return proposedContentOffset }

    let pageWidth = itemSize.width + minimumLineSpacing
    let currentPage: CGFloat = collectionView.contentOffset.x / pageWidth
    let nearestPage: CGFloat = round(currentPage)
    let isNearPreviousPage = nearestPage < currentPage

    var pageDiff: CGFloat = 0
    let velocityThreshold: CGFloat = 0.5 // can customize this threshold
    if isNearPreviousPage {
      if velocity.x > velocityThreshold {
        pageDiff = 1
      }
    } else {
      if velocity.x < -velocityThreshold {
        pageDiff = -1
      }
    }

    let x = (nearestPage + pageDiff) * pageWidth
    let cappedX = max(0, x) // cap to avoid targeting beyond content
    //print("x:", x, "velocity:", velocity)
    return CGPoint(x: cappedX, y: proposedContentOffset.y)
  }

}

-1

আপনি নিম্নলিখিত গ্রন্থাগারটি ব্যবহার করতে পারেন: https://github.com/ink-spot/UPCarouselFlowLayout

এটি খুব সহজ এবং আপনার অন্যান্য উত্তরগুলির মতো বিশদ সম্পর্কে ভাবার দরকার নেই।


-1

আমি এখানে একটি কাস্টম সংগ্রহ ভিউ লেআউট তৈরি করেছি যা সমর্থন করে:

  • একবারে একটি ঘরে পেজিং করা
  • সোয়াইপের বেগের উপর নির্ভর করে একসাথে 2+ সেল পেজিং করুন
  • অনুভূমিক বা উল্লম্ব দিক

এটি যেমন সহজ:

let layout = PagingCollectionViewLayout()

layout.itemSize = 
layout.minimumLineSpacing = 
layout.scrollDirection = 

আপনি কেবলমাত্র আপনার প্রকল্পে পেজিংকলেকশনভিউলয়আউট.সুইফ্ট যুক্ত করতে পারেন

অথবা

pod 'PagingCollectionViewLayout'আপনার পোডফাইলে যোগ করুন

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.