টার্গেট কনটেন্টঅফসেটফোর্ডপ্রপোজড কনটেন্টঅফসেট: ইউক্রোলিকেশন ভিউফ্লোএলআউট সাবক্লাসিং ছাড়াই স্ক্রোলিংভেলসিটি সহ


100

আমি আমার অ্যাপ্লিকেশনটিতে একটি খুব সাধারণ সংগ্রহ ভিউ পেয়েছি (বর্গক্ষেত্রের থাম্বনেল চিত্রগুলির মধ্যে একটি মাত্র সারি)।

আমি স্ক্রোলিংটি আটকাতে চাই যাতে অফসেট সর্বদা বাম পাশে একটি পূর্ণ চিত্র ফেলে দেয়। এই মুহুর্তে এটি যেখানেই স্ক্রোল করে এবং কাটা চিত্রগুলি ছাড়বে।

যাইহোক, আমি জানি আমার ফাংশনটি ব্যবহার করা দরকার

- (CGPoint)targetContentOffsetForProposedContentOffset:withScrollingVelocity

এটি করতে তবে আমি কেবল একটি মান ব্যবহার করছি UICollectionViewFlowLayout। আমি এটি সাবক্লাসিং করছি না।

সাবক্লাসিং ছাড়াই কি এটিকে বাধা দেওয়ার কোনও উপায় আছে UICollectionViewFlowLayout?

ধন্যবাদ

উত্তর:


114

ঠিক আছে, উত্তর নেই, ইউআইকোলিকেশনভিউফ্লোলোআউটটি সাবক্লাসিং না করে এটি করার কোনও উপায় নেই।

তবে, ভবিষ্যতে যারা এটি পড়ছেন তাদের পক্ষে এটি সাবক্লাসিং অবিশ্বাস্যরকম সহজ easy

প্রথমে আমি সাবক্লাস কল সেট আপ করেছি MyCollectionViewFlowLayoutএবং তারপরে ইন্টারফেস বিল্ডারে আমি সংগ্রহের ভিউ লেআউটটিকে কাস্টমতে পরিবর্তন করেছি এবং আমার ফ্লো লেআউট সাবক্লাসটি নির্বাচন করেছি।

কারণ আপনি এটি এইভাবে করছেন আপনি আইটেমের আকারগুলি ইত্যাদি নির্দিষ্ট করতে পারবেন না ... আইবিতে তাই মাই ক্লেকশনভিউফ্লোলায়আউট.এম এ আমার আছে ...

- (void)awakeFromNib
{
    self.itemSize = CGSizeMake(75.0, 75.0);
    self.minimumInteritemSpacing = 10.0;
    self.minimumLineSpacing = 10.0;
    self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
    self.sectionInset = UIEdgeInsetsMake(10.0, 10.0, 10.0, 10.0);
}

এটি আমার এবং স্ক্রোলের দিকের জন্য সমস্ত আকার নির্ধারণ করে।

তারপরে ...

- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
{
    CGFloat offsetAdjustment = MAXFLOAT;
    CGFloat horizontalOffset = proposedContentOffset.x + 5;

    CGRect targetRect = CGRectMake(proposedContentOffset.x, 0, self.collectionView.bounds.size.width, self.collectionView.bounds.size.height);

    NSArray *array = [super layoutAttributesForElementsInRect:targetRect];

    for (UICollectionViewLayoutAttributes *layoutAttributes in array) {
        CGFloat itemOffset = layoutAttributes.frame.origin.x;
        if (ABS(itemOffset - horizontalOffset) < ABS(offsetAdjustment)) {
            offsetAdjustment = itemOffset - horizontalOffset;
        }
    }

    return CGPointMake(proposedContentOffset.x + offsetAdjustment, proposedContentOffset.y);
}

এটি নিশ্চিত করে যে বাম হাতের প্রান্তে 5.0 এর মার্জিনের সাথে স্ক্রোলিংটি শেষ হবে।

আমার যা করা দরকার তা-ই। আমার কোডে ফ্লো লেআউট সেট করার দরকার নেই।


4
সঠিকভাবে ব্যবহার করা হলে এটি সত্যই শক্তিশালী। আপনি কি ডাব্লুডাব্লুডিসি 2012 থেকে সংগ্রহ দেখুন সেশনগুলি দেখেছেন? তারা সত্যিই দেখার মূল্য। কিছু অবিশ্বাস্য জিনিস।
ফোগমিস্টার

4
targetContentOffsetForProposedContentOffset:withVelocityআমি যখন স্ক্রোল করব তখন আমার জন্য ডাকা হচ্ছে না। কি হচ্ছে?
ফতুহোকু

4
@ টমসওয়ায়ার ইউআইসোক্লোলভিউ'র ঘোষণার হারকে ইউআইএসক্রোলভিউডিজলেশনরেটফাস্টে সেট করেছে।
ক্লে এলিস

4
@ ফাতুহোকু নিশ্চিত করুন যে আপনার সংগ্রহভিউর প্যাগইনএবলিত সম্পত্তিটি মিথ্যাতে সেট করা আছে
chr

4
হোলি মলি, এই উত্তরটি দেখতে আমাকে মিলিয়ন মাইলের মতো স্ক্রোল করতে হয়েছিল। :)
অ্যানবিসউ

67

ড্যানের সমাধানটি ত্রুটিযুক্ত। এটি ব্যবহারকারীর ভালভাবে ঝাঁকুনি পরিচালনা করে না। যে ক্ষেত্রে ব্যবহারকারীরা দ্রুত ফ্লিক করে এবং স্ক্রোলটি এতটা সরে যায় না, অ্যানিমেশন গ্লিটস থাকে।

আমার প্রস্তাবিত বিকল্প বাস্তবায়নের আগের প্রস্তাবিত একই পৃষ্ঠাগুলি রয়েছে, তবে পৃষ্ঠাগুলির মধ্যে থাকা ব্যবহারকারীদের হাতছাড়া করা পরিচালনা করে।

 #pragma mark - Pagination
 - (CGFloat)pageWidth {
     return self.itemSize.width + self.minimumLineSpacing;
 }

 - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
 {           
        CGFloat rawPageValue = self.collectionView.contentOffset.x / self.pageWidth;
        CGFloat currentPage = (velocity.x > 0.0) ? floor(rawPageValue) : ceil(rawPageValue);
        CGFloat nextPage = (velocity.x > 0.0) ? ceil(rawPageValue) : floor(rawPageValue);

        BOOL pannedLessThanAPage = fabs(1 + currentPage - rawPageValue) > 0.5;
        BOOL flicked = fabs(velocity.x) > [self flickVelocity];
        if (pannedLessThanAPage && flicked) {
            proposedContentOffset.x = nextPage * self.pageWidth;
        } else {
            proposedContentOffset.x = round(rawPageValue) * self.pageWidth;
        }

        return proposedContentOffset;
 }

 - (CGFloat)flickVelocity {
     return 0.3;
 }

ধন্যবাদ! এটা চমত্কার ভাবে কাজ করেছে. কিছুটা বুঝতে অসুবিধা হলেও সেখানে পৌঁছে যাচ্ছি।
রাজীব তিমাল 18 ই

আমার এই ত্রুটি হচ্ছে: 'প্রস্তাবিত কনটেন্টঅফসেট'-এ' এক্স 'বরাদ্দ করা যায় না? দ্রুত ব্যবহার করছেন? আমি এক্স মান নির্ধারণ করতে পারেন কিভাবে?
টমসওয়ায়ার

@ টমসওয়ের প্যারামগুলি ডিফল্টরূপে 'চলুন' are Func targetContentOffsetForProposedContentOffset ওভাররাইড: -> CGPoint (Var proposedContentOffset: CGPoint) সুইফট এই যেমন ফাংশন ডিক্লেয়ার (PARAM আগে Var ব্যবহার করে) ব্যবহার করে দেখুন
DarthMike

4
আপনি দ্রুতগতিতে সিজিপিয়েন্টম্যানকে ব্যবহার করতে পারবেন না। আমি ব্যক্তিগতভাবে এটি ব্যবহার করেছি: "var টার্গেটকন্টেন্ট অফসেট: সিজিপয়েন্ট যদি প্যানডলেসথানপেজ && এড়ান {টার্গেটকন্টেন্টঅফসেট = সিজিপিয়েন্ট (এক্স: নেক্সটপেজ * পৃষ্ঠাউইথ (), y: প্রস্তাবিতকন্টেন্টঅফসেট.ইপি);} অন্য {টার্গেটকন্টেন্টঅফসেট = সিজিপিউনটি (এক্সপি) (কাচপেজভিজভিড ), y: প্রস্তাবিত কনটেন্টঅফসেট.ই); proposed প্রস্তাবিত
প্লট

4
এটি নির্বাচিত উত্তর হওয়া উচিত।
খুনশান

26

গৃহীত উত্তরের দ্রুততম সংস্করণ।

override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
    var offsetAdjustment = CGFloat.greatestFiniteMagnitude
    let horizontalOffset = proposedContentOffset.x
    let targetRect = CGRect(origin: CGPoint(x: proposedContentOffset.x, y: 0), size: self.collectionView!.bounds.size)

    for layoutAttributes in super.layoutAttributesForElements(in: targetRect)! {
        let itemOffset = layoutAttributes.frame.origin.x
        if (abs(itemOffset - horizontalOffset) < abs(offsetAdjustment)) {
            offsetAdjustment = itemOffset - horizontalOffset
        }
    }

    return CGPoint(x: proposedContentOffset.x + offsetAdjustment, y: proposedContentOffset.y)
}    

সুইফট 5 এর জন্য বৈধ ।


এই সংস্করণটি দুর্দান্ত কাজ করে এবং যদি আপনি কোডটি চারপাশে অদলবদল করেন তবে এটি Y অক্ষের জন্যও ভাল কাজ করে।
ক্রিস

বেশিরভাগই এখানে দুর্দান্ত কাজ করে। তবে আমি যদি স্ক্রোলিং বন্ধ করি এবং আমার আঙুলটি (সাবধানে) তুলি তবে এটি কোনও পৃষ্ঠায় স্ক্রোল করে কেবল সেখানে থামবে না।
খ্রিস্টান এ। Strømmen

@ খ্রিস্টানএ.সেট্র্যামেন অদ্ভুত, এটি আমার অ্যাপ্লিকেশনটির সাথে ঠিক কাজ করে।
আন্দ্রে আব্রেউ

@ আন্দ্রেআব্রেবু আমি এই ফাংশনটি কোথায় রাখব?
ফ্লোইউআই সরলইউইটিস্টিং.কম

4
@ জায়ে আপনাকে ইউআইকোলিকেশনভিউলাওআউট বা যে কোনও শ্রেণি ইতিমধ্যে এটি সাবক্লাস করতে হবে (যেমন ইউআইকোলিকেশনভিউফ্লোলোআউট) সাবক্লাস করতে হবে।
আন্দ্রে আব্রেউ

24

উল্লম্ব সেল-ভিত্তিক পেজিংয়ের জন্য সুইফট 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)
}

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


4
আপনি জীবন রক্ষাকারী! সেট করার জন্য জাল করা জরুরী নোট গুরুত্বপূর্ণ! আমার জীবনের 2 ঘন্টার মতো হারিয়ে গেছে আপনার ফাংশনটি ঠিক করছে যা ইতিমধ্যে কাজ করে ...
denis631

@ denis631 আমি দুঃখিত! আমার এটি যোগ করা উচিত ছিল, আমি এটি প্রতিফলিত করতে পোস্ট সম্পাদনা করব! খুশী হয়ে কাজ করেছে :)
JoniVR

জেসুস, আমি ভাবছিলাম যে পেজিং অক্ষম করার বিষয়ে এই মন্তব্যটি না দেখলে কেন এটি কাজ করছে না ... অবশ্যই আমার সত্য হয়ে গেছে
কাম ওও

@ জোনিভিআর এটি আমাকে দেখায় যে এই ত্রুটি পদ্ধতিটি তার সুপারক্লাস থেকে কোনও পদ্ধতি ওভাররাইড করে না
মুজু

22

যদিও এই উত্তরটি আমার পক্ষে দুর্দান্ত সহায়ক হয়েছে, আপনি যখন অল্প দূরত্বে দ্রুত সোয়াইপ করেন তখন একটি লক্ষণীয় ঝাঁকুনি থাকে। এটি ডিভাইসে পুনরুত্পাদন করা অনেক সহজ।

আমি খুঁজে পেয়েছি যে যখন সর্বদা আলাদা হয় collectionView.contentOffset.x - proposedContentOffset.xএবং velocity.xবিভিন্ন গান হয়।

আমার সমাধানটি ছিল বেগটি ইতিবাচক হলে proposedContentOffsetতার চেয়ে বেশি contentOffset.xএবং এটি নেতিবাচক হলে কম ensure এটি সি # তে কিন্তু উদ্দেশ্য সিতে অনুবাদ করা মোটামুটি সহজ হওয়া উচিত:

public override PointF TargetContentOffset (PointF proposedContentOffset, PointF scrollingVelocity)
{
    /* Determine closest edge */

    float offSetAdjustment = float.MaxValue;
    float horizontalCenter = (float) (proposedContentOffset.X + (this.CollectionView.Bounds.Size.Width / 2.0));

    RectangleF targetRect = new RectangleF (proposedContentOffset.X, 0.0f, this.CollectionView.Bounds.Size.Width, this.CollectionView.Bounds.Size.Height);
    var array = base.LayoutAttributesForElementsInRect (targetRect);

    foreach (var layoutAttributes in array) {
        float itemHorizontalCenter = layoutAttributes.Center.X;
        if (Math.Abs (itemHorizontalCenter - horizontalCenter) < Math.Abs (offSetAdjustment)) {
            offSetAdjustment = itemHorizontalCenter - horizontalCenter;
        }
    }

    float nextOffset = proposedContentOffset.X + offSetAdjustment;

    /*
     * ... unless we end up having positive speed
     * while moving left or negative speed while moving right.
     * This will cause flicker so we resort to finding next page
     * in the direction of velocity and use it.
     */

    do {
        proposedContentOffset.X = nextOffset;

        float deltaX = proposedContentOffset.X - CollectionView.ContentOffset.X;
        float velX = scrollingVelocity.X;

        // If their signs are same, or if either is zero, go ahead
        if (Math.Sign (deltaX) * Math.Sign (velX) != -1)
            break;

        // Otherwise, look for the closest page in the right direction
        nextOffset += Math.Sign (scrollingVelocity.X) * SnapStep;
    } while (IsValidOffset (nextOffset));

    return proposedContentOffset;
}

bool IsValidOffset (float offset)
{
    return (offset >= MinContentOffset && offset <= MaxContentOffset);
}

এই কোড ব্যবহার করছে MinContentOffset, MaxContentOffsetএবং SnapStepযা তুচ্ছ আপনি সংজ্ঞায়িত করার জন্য হওয়া উচিত। আমার ক্ষেত্রে তারা পরিণত হয়েছে

float MinContentOffset {
    get { return -CollectionView.ContentInset.Left; }
}

float MaxContentOffset {
    get { return MinContentOffset + CollectionView.ContentSize.Width - ItemSize.Width; }
}

float SnapStep {
    get { return ItemSize.Width + MinimumLineSpacing; }
}

7
এটি সত্যিই ভাল কাজ করে। যারা আগ্রহী তাদের জন্য আমি এটি উদ্দেশ্যমূলক-সিতে রূপান্তর করেছি: gist.github.com/rkeniger/7687301
রব কেনেগার

21

দীর্ঘ পরীক্ষার পরে আমি কাস্টম সেল প্রস্থের (প্রতিটি ঘরের পৃথক প্রস্থ রয়েছে) কেন্দ্রের মধ্যে স্ন্যাপ করার সমাধান পেয়েছি যা ঝাঁকুনির সমাধান করে। স্ক্রিপ্ট উন্নত নির্দ্বিধায়।

- (CGPoint) targetContentOffsetForProposedContentOffset: (CGPoint) proposedContentOffset withScrollingVelocity: (CGPoint)velocity
{
    CGFloat offSetAdjustment = MAXFLOAT;
    CGFloat horizontalCenter = (CGFloat) (proposedContentOffset.x + (self.collectionView.bounds.size.width / 2.0));

    //setting fastPaging property to NO allows to stop at page on screen (I have pages lees, than self.collectionView.bounds.size.width)
    CGRect targetRect = CGRectMake(self.fastPaging ? proposedContentOffset.x : self.collectionView.contentOffset.x, 
                                   0.0,
                                   self.collectionView.bounds.size.width,
                                   self.collectionView.bounds.size.height);

    NSArray *attributes = [self layoutAttributesForElementsInRect:targetRect];
    NSPredicate *cellAttributesPredicate = [NSPredicate predicateWithBlock: ^BOOL(UICollectionViewLayoutAttributes * _Nonnull evaluatedObject,
                                                                             NSDictionary<NSString *,id> * _Nullable bindings) 
    {
        return (evaluatedObject.representedElementCategory == UICollectionElementCategoryCell); 
    }];        

    NSArray *cellAttributes = [attributes filteredArrayUsingPredicate: cellAttributesPredicate];

    UICollectionViewLayoutAttributes *currentAttributes;

    for (UICollectionViewLayoutAttributes *layoutAttributes in cellAttributes)
    {
        CGFloat itemHorizontalCenter = layoutAttributes.center.x;
        if (ABS(itemHorizontalCenter - horizontalCenter) < ABS(offSetAdjustment))
        {
            currentAttributes   = layoutAttributes;
            offSetAdjustment    = itemHorizontalCenter - horizontalCenter;
        }
    }

    CGFloat nextOffset          = proposedContentOffset.x + offSetAdjustment;

    proposedContentOffset.x     = nextOffset;
    CGFloat deltaX              = proposedContentOffset.x - self.collectionView.contentOffset.x;
    CGFloat velX                = velocity.x;

    // detection form  gist.github.com/rkeniger/7687301
    // based on http://stackoverflow.com/a/14291208/740949
    if (fabs(deltaX) <= FLT_EPSILON || fabs(velX) <= FLT_EPSILON || (velX > 0.0 && deltaX > 0.0) || (velX < 0.0 && deltaX < 0.0)) 
    {

    } 
    else if (velocity.x > 0.0) 
    {
       // revert the array to get the cells from the right side, fixes not correct center on different size in some usecases
        NSArray *revertedArray = [[array reverseObjectEnumerator] allObjects];

        BOOL found = YES;
        float proposedX = 0.0;

        for (UICollectionViewLayoutAttributes *layoutAttributes in revertedArray)
        {
            if(layoutAttributes.representedElementCategory == UICollectionElementCategoryCell)
            {
                CGFloat itemHorizontalCenter = layoutAttributes.center.x;
                if (itemHorizontalCenter > proposedContentOffset.x) {
                     found = YES;
                     proposedX = nextOffset + (currentAttributes.frame.size.width / 2) + (layoutAttributes.frame.size.width / 2);
                } else {
                     break;
                }
            }
        }

       // dont set on unfound element
        if (found) {
            proposedContentOffset.x = proposedX;
        }
    } 
    else if (velocity.x < 0.0) 
    {
        for (UICollectionViewLayoutAttributes *layoutAttributes in cellAttributes)
        {
            CGFloat itemHorizontalCenter = layoutAttributes.center.x;
            if (itemHorizontalCenter > proposedContentOffset.x) 
            {
                proposedContentOffset.x = nextOffset - ((currentAttributes.frame.size.width / 2) + (layoutAttributes.frame.size.width / 2));
                break;
            }
        }
    }

    proposedContentOffset.y = 0.0;

    return proposedContentOffset;
}

10
তাদের সবার সেরা সমাধান, ধন্যবাদ! ভবিষ্যতের যে কোনও পাঠকের কাছেও এটি কাজ করার জন্য আপনাকে অবশ্যই পেজিং বন্ধ করতে হবে।
শ্রীদেবজয় 19

4
যদি কেউ কেন্দ্রে ডানদিকে ডানদিকে প্রান্তিককরণের পরিবর্তে বাম থেকে এটি সারিবদ্ধ করতে চান তবে আমরা কীভাবে এটি পরিবর্তন করব?
সাইবারমিউ

আমি সঠিকভাবে বুঝতে পেরেছি কিনা তা নিশ্চিত না, তবে আপনি যদি আইটেমগুলিকে কেন্দ্র করে শুরু করতে চান এবং এটি কেন্দ্রে সারিবদ্ধ করতে চান তবে আপনার বিষয়বস্তু পরিবর্তন করতে হবে ইনসেট। আমি এটি ব্যবহার করি: gist.github.com/pionl/432fc8059dee3b540e38
পিয়ন

ঘরের মাঝামাঝি কক্ষের এক্স অবস্থানে সারিবদ্ধ করতে, কেবল বেগ বিভাগে + (লেআউটআট্রিবিউটস.ফ্রেম.সাইজ.উইথ / 2) সরান।
পিওন

4
@ হাই হাই, কেবলমাত্র একটি কাস্টম ফ্লো প্রতিনিধি তৈরি করুন এবং এতে এই কোডটি যুক্ত করুন। নিব বা কোডে কাস্টম লেআউট সেট করতে ভুলবেন না।
পিয়ন

18

পড়ুন ড্যান Abramov দ্বারা এই উত্তরটি এখানে সুইফট সংস্করণ

    override func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
    var _proposedContentOffset = CGPoint(x: proposedContentOffset.x, y: proposedContentOffset.y)
    var offSetAdjustment: CGFloat = CGFloat.max
    let horizontalCenter: CGFloat = CGFloat(proposedContentOffset.x + (self.collectionView!.bounds.size.width / 2.0))

    let targetRect = CGRect(x: proposedContentOffset.x, y: 0.0, width: self.collectionView!.bounds.size.width, height: self.collectionView!.bounds.size.height)

    let array: [UICollectionViewLayoutAttributes] = self.layoutAttributesForElementsInRect(targetRect)! as [UICollectionViewLayoutAttributes]
    for layoutAttributes: UICollectionViewLayoutAttributes in array {
        if (layoutAttributes.representedElementCategory == UICollectionElementCategory.Cell) {
            let itemHorizontalCenter: CGFloat = layoutAttributes.center.x
            if (abs(itemHorizontalCenter - horizontalCenter) < abs(offSetAdjustment)) {
                offSetAdjustment = itemHorizontalCenter - horizontalCenter
            }
        }
    }

    var nextOffset: CGFloat = proposedContentOffset.x + offSetAdjustment

    repeat {
        _proposedContentOffset.x = nextOffset
        let deltaX = proposedContentOffset.x - self.collectionView!.contentOffset.x
        let velX = velocity.x

        if (deltaX == 0.0 || velX == 0 || (velX > 0.0 && deltaX > 0.0) || (velX < 0.0 && deltaX < 0.0)) {
            break
        }

        if (velocity.x > 0.0) {
            nextOffset = nextOffset + self.snapStep()
        } else if (velocity.x < 0.0) {
            nextOffset = nextOffset - self.snapStep()
        }
    } while self.isValidOffset(nextOffset)

    _proposedContentOffset.y = 0.0

    return _proposedContentOffset
}

func isValidOffset(offset: CGFloat) -> Bool {
    return (offset >= CGFloat(self.minContentOffset()) && offset <= CGFloat(self.maxContentOffset()))
}

func minContentOffset() -> CGFloat {
    return -CGFloat(self.collectionView!.contentInset.left)
}

func maxContentOffset() -> CGFloat {
    return CGFloat(self.minContentOffset() + self.collectionView!.contentSize.width - self.itemSize.width)
}

func snapStep() -> CGFloat {
    return self.itemSize.width + self.minimumLineSpacing;
}

বা এখানে প্রকাশ করুন https://gist.github.com/katopz/8b04c783387f0c345cd9


4
সুইফট 3 এর জন্য এটির
mstubna

4
ডাং ইট @ মস্তুবনা, আমি এগিয়ে গিয়ে উপরেরটি অনুলিপি করেছি, এটিকে সুইফট 3 এ আপডেট করেছি, একটি আপডেট গিস্ট তৈরি করতে শুরু করেছিলাম এবং নোটস / শিরোনাম সংগ্রহ করতে এখানে ফিরে এসেছি যেখানে আমি লক্ষ্য করেছি যে আপনি ইতিমধ্যে একটি সুইফট 3 গিস্ট তৈরি করেছেন। ধন্যবাদ! খুব খারাপ আমি এটি মিস করেছি।
ভ্যাপারওয়ারওয়াল্ফ

18

যে কেউ সমাধানের সন্ধান করছেন তার জন্য ...

  • যখন ব্যবহারকারী একটি স্বল্প দ্রুত স্ক্রোল সঞ্চালন করে তখন আনন্দিত হয় না (যেমন এটি ইতিবাচক এবং নেতিবাচক স্ক্রোলের বেগ বিবেচনা করে)
  • লাগে collectionView.contentInset(এবং safeArea আইফোন এক্স দিকে) বিবেচনা
  • কেবল থ্রোল সেলগুলি স্ক্রোলিংয়ের স্থানে দৃশ্যমান বিবেচনা করে (পামফর্মের জন্য)
  • ভাল নামযুক্ত ভেরিয়েবল এবং মন্তব্য ব্যবহার করে
  • সুইফট 4

তাহলে দয়া করে নীচে দেখুন ...

public class CarouselCollectionViewLayout: UICollectionViewFlowLayout {

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

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

        // Identify the layoutAttributes of cells in the vicinity of where the scroll view will come to rest
        let targetRect = CGRect(origin: proposedContentOffset, size: collectionView.bounds.size)
        let visibleCellsLayoutAttributes = layoutAttributesForElements(in: targetRect)

        // Translate those cell layoutAttributes into potential (candidate) scrollView offsets
        let candidateOffsets: [CGFloat]? = visibleCellsLayoutAttributes?.map({ cellLayoutAttributes in
            if #available(iOS 11.0, *) {
                return cellLayoutAttributes.frame.origin.x - collectionView.contentInset.left - collectionView.safeAreaInsets.left - sectionInset.left
            } else {
                return cellLayoutAttributes.frame.origin.x - collectionView.contentInset.left - sectionInset.left
            }
        })

        // Now we need to work out which one of the candidate offsets is the best one
        let bestCandidateOffset: CGFloat

        if velocity.x > 0 {
            // If the scroll velocity was POSITIVE, then only consider cells/offsets to the RIGHT of the proposedContentOffset.x
            // Of the cells/offsets to the right, the NEAREST is the `bestCandidate`
            // If there is no nearestCandidateOffsetToLeft then we default to the RIGHT-MOST (last) of ALL the candidate cells/offsets
            //      (this handles the scenario where the user has scrolled beyond the last cell)
            let candidateOffsetsToRight = candidateOffsets?.toRight(ofProposedOffset: proposedContentOffset.x)
            let nearestCandidateOffsetToRight = candidateOffsetsToRight?.nearest(toProposedOffset: proposedContentOffset.x)
            bestCandidateOffset = nearestCandidateOffsetToRight ?? candidateOffsets?.last ?? proposedContentOffset.x
        }
        else if velocity.x < 0 {
            // If the scroll velocity was NEGATIVE, then only consider cells/offsets to the LEFT of the proposedContentOffset.x
            // Of the cells/offsets to the left, the NEAREST is the `bestCandidate`
            // If there is no nearestCandidateOffsetToLeft then we default to the LEFT-MOST (first) of ALL the candidate cells/offsets
            //      (this handles the scenario where the user has scrolled beyond the first cell)
            let candidateOffsetsToLeft = candidateOffsets?.toLeft(ofProposedOffset: proposedContentOffset.x)
            let nearestCandidateOffsetToLeft = candidateOffsetsToLeft?.nearest(toProposedOffset: proposedContentOffset.x)
            bestCandidateOffset = nearestCandidateOffsetToLeft ?? candidateOffsets?.first ?? proposedContentOffset.x
        }
        else {
            // If the scroll velocity was ZERO we consider all `candidate` cells (regarless of whether they are to the left OR right of the proposedContentOffset.x)
            // The cell/offset that is the NEAREST is the `bestCandidate`
            let nearestCandidateOffset = candidateOffsets?.nearest(toProposedOffset: proposedContentOffset.x)
            bestCandidateOffset = nearestCandidateOffset ??  proposedContentOffset.x
        }

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

}

fileprivate extension Sequence where Iterator.Element == CGFloat {

    func toLeft(ofProposedOffset proposedOffset: CGFloat) -> [CGFloat] {

        return filter() { candidateOffset in
            return candidateOffset < proposedOffset
        }
    }

    func toRight(ofProposedOffset proposedOffset: CGFloat) -> [CGFloat] {

        return filter() { candidateOffset in
            return candidateOffset > proposedOffset
        }
    }

    func nearest(toProposedOffset proposedOffset: CGFloat) -> CGFloat? {

        guard let firstCandidateOffset = first(where: { _ in true }) else {
            // If there are no elements in the Sequence, return nil
            return nil
        }

        return reduce(firstCandidateOffset) { (bestCandidateOffset: CGFloat, candidateOffset: CGFloat) -> CGFloat in

            let candidateOffsetDistanceFromProposed = fabs(candidateOffset - proposedOffset)
            let bestCandidateOffsetDistancFromProposed = fabs(bestCandidateOffset - proposedOffset)

            if candidateOffsetDistanceFromProposed < bestCandidateOffsetDistancFromProposed {
                return candidateOffset
            }

            return bestCandidateOffset
        }
    }
}

4
ধন্যবাদ! ঠিক অনুলিপি করা হয়েছে এবং আটকানো হয়েছে, নিখুঁতভাবে কাজ করছে ... প্রত্যাশার চেয়ে ভাল way
স্টিভেন বি

4
একমাত্র এবং একমাত্র সমাধান যা আসলে কাজ করে। সুন্দর চাকরি! ধন্যবাদ!
লিনাসেফার্থ্থ

4
রিটার্ন cellLayoutAttributes.frame.origin.x - collectionView.contentInset.left - collectionView.safeAreaInsets.left candidateOffsets - sectionInset.left এই লাইনে একটা সমস্যা
Utku Dalmaz

4
@ ডালমাজ আমাকে অবহিত করার জন্য ধন্যবাদ। আমি এখনই বিষয়টি ঠিক করেছি।
অলিভার পিয়ারমাইন

4
হ্যাঁ, স্রেফ অনুলিপি করা হয়েছে এবং আটকানো হয়েছে, আপনি আমার সময় বাঁচান।
ওয়েই

7

অনুভূমিকভাবে স্ক্রোলিং সংগ্রহের দৃশ্যে আমার সুইফট সমাধানটি এখানে। এটি সাধারণ, মিষ্টি এবং কোনও ঝাঁকুনি এড়ানো।

  override func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
    guard let collectionView = collectionView else { return proposedContentOffset }

    let currentXOffset = collectionView.contentOffset.x
    let nextXOffset = proposedContentOffset.x
    let maxIndex = ceil(currentXOffset / pageWidth())
    let minIndex = floor(currentXOffset / pageWidth())

    var index: CGFloat = 0

    if nextXOffset > currentXOffset {
      index = maxIndex
    } else {
      index = minIndex
    }

    let xOffset = pageWidth() * index
    let point = CGPointMake(xOffset, 0)

    return point
  }

  func pageWidth() -> CGFloat {
    return itemSize.width + minimumInteritemSpacing
  }


এটি সংগ্রহ কক্ষগুলির আকার। এই ফাংশনটি ইউআইকোলিকেশনভিউফ্লোলয়আউট সাবক্লাস করার সময় ব্যবহৃত হয়।
স্কট কায়সার


4
আমি এই সমাধানটি পছন্দ করি তবে আমার কয়েকটি মন্তব্য আছে। এটি অনুভূমিকভাবে স্ক্রোল pageWidth()করার minimumLineSpacingপরে ব্যবহার করা উচিত । এবং আমার ক্ষেত্রে আমার contentInsetকাছে সংগ্রহের ভিউ রয়েছে যাতে প্রথম এবং শেষ কক্ষটি কেন্দ্রীভূত করা যায়, তাই আমি ব্যবহার করি let xOffset = pageWidth() * index - collectionView.contentInset.left
blinkters

6

টার্গেটকন্টেন্টএফসেটফর্মপ্রপোজড কনটেন্টঅফসেট ব্যবহার করার সময় একটি ছোট সমস্যা আমার মুখোমুখি হ'ল আমি ফিরে আসা নতুন পয়েন্ট অনুসারে শেষ কক্ষটি সামঞ্জস্য না করে with
আমি জানতে পেরেছিলাম যে সিজিপয়েন্ট আমি ফিরে এসেছি তার ওয়াইয়ের মান আরও বড় হয়ে গেছে তাই আমি আমার টার্গেটকন্টেন্ট অফসফটফর্মপ্রসেসকন্ট্যান্ট অফসেস বাস্তবায়ন শেষে নিম্নলিখিত কোডটি ব্যবহার করেছি:

// if the calculated y is bigger then the maximum possible y we adjust accordingly
CGFloat contentHeight = self.collectionViewContentSize.height;
CGFloat collectionViewHeight = self.collectionView.bounds.size.height;
CGFloat maxY = contentHeight - collectionViewHeight;
if (newY > maxY)
{
    newY = maxY;
}

return CGPointMake(0, newY);

কেবল এটি পরিষ্কার করার জন্য এটি আমার সম্পূর্ণ লেআউট বাস্তবায়ন যা কেবল উল্লম্ব পেজিং আচরণের অনুকরণ করে:

- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
{
    return [self targetContentOffsetForProposedContentOffset:proposedContentOffset];
}

- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset
{
    CGFloat heightOfPage = self.itemSize.height;
    CGFloat heightOfSpacing = self.minimumLineSpacing;

    CGFloat numOfPage = lround(proposedContentOffset.y / (heightOfPage + heightOfSpacing));
    CGFloat newY = numOfPage * (heightOfPage + heightOfSpacing);

    // if the calculated y is bigger then the maximum possible y we adjust accordingly
    CGFloat contentHeight = self.collectionViewContentSize.height;
    CGFloat collectionViewHeight = self.collectionView.bounds.size.height;
    CGFloat maxY = contentHeight - collectionViewHeight;
    if (newY > maxY)
    {
        newY = maxY;
    }

    return CGPointMake(0, newY);
}

আশা করি এটি কারও কিছুটা সময় ও মাথা ব্যথা বাঁচাবে


4
একই সমস্যা, দেখে মনে হচ্ছে সংগ্রহের ভিউ অবৈধ মানগুলিকে এটিকে তার সীমানায় ঘোরানোর পরিবর্তে অগ্রাহ্য করবে।
মাইক এম

6

আমি বেশ কয়েকটি পৃষ্ঠায় ব্যবহারকারীদের ফ্লিকিংয়ের অনুমতি দিতে পছন্দ করি। সুতরাং উল্লম্ব লেআউটটির targetContentOffsetForProposedContentOffsetজন্য এখানে আমার সংস্করণটি (যা দার্থমাইক উত্তরের উপর ভিত্তি করে) রয়েছে ।

- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity {
    CGFloat approximatePage = self.collectionView.contentOffset.y / self.pageHeight;
    CGFloat currentPage = (velocity.y < 0.0) ? floor(approximatePage) : ceil(approximatePage);

    NSInteger flickedPages = ceil(velocity.y / self.flickVelocity);

    if (flickedPages) {
        proposedContentOffset.y = (currentPage + flickedPages) * self.pageHeight;
    } else {
        proposedContentOffset.y = currentPage * self.pageHeight;
    }

    return proposedContentOffset;
}

- (CGFloat)pageHeight {
    return self.itemSize.height + self.minimumLineSpacing;
}

- (CGFloat)flickVelocity {
    return 1.2;
}

4

আমি সারিটির শেষ দিকে স্ক্রোল না করে ফোগমিটারের উত্তর আমার পক্ষে কাজ করেছে। আমার কোষগুলি স্ক্রিনে খুব সুন্দরভাবে ফিট করে না তাই এটি শেষ পর্যন্ত স্ক্রোল করে কোনও ঝাঁকুনি দিয়ে পিছনে ঝাঁপিয়ে পড়ে যাতে শেষ কক্ষটি সর্বদা পর্দার ডান প্রান্তকে ওভারল্যাপ করে।

এটি রোধ করতে টার্গেটকন্টিঅন্টসেট পদ্ধতিটি শুরুতে নিম্নলিখিত কোডের লাইন যুক্ত করুন

if(proposedContentOffset.x>self.collectionViewContentSize.width-320-self.sectionInset.right)
    return proposedContentOffset;

আমি মনে করি 320 হল আপনার সংগ্রহ দেখার প্রস্থ :)
আউ রিস

পুরানো কোডটি ফিরে চেয়ে ভাল লাগল। আমার ধারণা যে ম্যাজিক নম্বরটি ছিল।
আজাক্সর্গ

2

@ আন্দ্রে আব্রেয়ের কোড

সুইফট 3 সংস্করণ

class CustomCollectionViewFlowLayout: UICollectionViewFlowLayout {
    override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
        var offsetAdjustment = CGFloat.greatestFiniteMagnitude
        let horizontalOffset = proposedContentOffset.x
        let targetRect = CGRect(x: proposedContentOffset.x, y: 0, width: self.collectionView!.bounds.size.width, height: self.collectionView!.bounds.size.height)
        for layoutAttributes in super.layoutAttributesForElements(in: targetRect)! {
            let itemOffset = layoutAttributes.frame.origin.x
            if abs(itemOffset - horizontalOffset) < abs(offsetAdjustment){
                offsetAdjustment = itemOffset - horizontalOffset
            }
        }
        return CGPoint(x: proposedContentOffset.x + offsetAdjustment, y: proposedContentOffset.y)
    }
}

তার জন্য ধন্যবাদ! সেরা আচরণ প্রত্যাশিত ধন্যবাদ এটি অনেক সাহায্য!
জি ক্লোভস

2

সুইফট 4

এক আকারের (অনুভূমিক স্ক্রোল) কক্ষগুলি সহ সংগ্রহ দেখার জন্য সহজ সমাধান:

override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
    guard let collectionView = collectionView else { return proposedContentOffset }

    // Calculate width of your page
    let pageWidth = calculatedPageWidth()

    // Calculate proposed page
    let proposedPage = round(proposedContentOffset.x / pageWidth)

    // Adjust necessary offset
    let xOffset = pageWidth * proposedPage - collectionView.contentInset.left

    return CGPoint(x: xOffset, y: 0)
}

func calculatedPageWidth() -> CGFloat {
    return itemSize.width + minimumInteritemSpacing
}

2

একটি সংক্ষিপ্ত সমাধান (ধরে নিচ্ছেন যে আপনি আপনার বিন্যাসের বৈশিষ্ট্যগুলি ক্যাশে করছেন):

override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
    let proposedEndFrame = CGRect(x: proposedContentOffset.x, y: 0, width: collectionView!.bounds.width, height: collectionView!.bounds.height)
    let targetLayoutAttributes = cache.max { $0.frame.intersection(proposedEndFrame).width < $1.frame.intersection(proposedEndFrame).width }!
    return CGPoint(x: targetLayoutAttributes.frame.minX - horizontalPadding, y: 0)
}

এটিকে প্রসঙ্গে রাখতে:

class Layout : UICollectionViewLayout {
    private var cache: [UICollectionViewLayoutAttributes] = []
    private static let horizontalPadding: CGFloat = 16
    private static let interItemSpacing: CGFloat = 8

    override func prepare() {
        let (itemWidth, itemHeight) = (collectionView!.bounds.width - 2 * Layout.horizontalPadding, collectionView!.bounds.height)
        cache.removeAll()
        let count = collectionView!.numberOfItems(inSection: 0)
        var x: CGFloat = Layout.horizontalPadding
        for item in (0..<count) {
            let indexPath = IndexPath(item: item, section: 0)
            let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
            attributes.frame = CGRect(x: x, y: 0, width: itemWidth, height: itemHeight)
            cache.append(attributes)
            x += itemWidth + Layout.interItemSpacing
        }
    }

    override var collectionViewContentSize: CGSize {
        let width: CGFloat
        if let maxX = cache.last?.frame.maxX {
            width = maxX + Layout.horizontalPadding
        } else {
            width = collectionView!.width
        }
        return CGSize(width: width, height: collectionView!.height)
    }

    override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        return cache.first { $0.indexPath == indexPath }
    }

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        return cache.filter { $0.frame.intersects(rect) }
    }

    override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
        let proposedEndFrame = CGRect(x: proposedContentOffset.x, y: 0, width: collectionView!.bounds.width, height: collectionView!.bounds.height)
        let targetLayoutAttributes = cache.max { $0.frame.intersection(proposedEndFrame).width < $1.frame.intersection(proposedEndFrame).width }!
        return CGPoint(x: targetLayoutAttributes.frame.minX - Layout.horizontalPadding, y: 0)
    }
}

1

এটি সুইফ্ট সংস্করণে (এখনই সুইফ্ট 5) কাজ করে তা নিশ্চিত করার জন্য, আমি উত্তরটি ব্যবহার করেছি @ আন্দ্রে অ্যাব্রেয়ের করেছি, আমি আরও কিছু তথ্য যুক্ত করছি:

ইউআইসি কলিকেশনভিউফ্লোলোআউট উপশ্রাহীকরণ করার সময়, "ওভাররাইড ফানক জাগানোফ্রমনিব () doesn't works" কাজ করে না (কেন জানি না)। পরিবর্তে, আমি "ওভাররাইড থিম () {সুপার ইন্ডিট ()}" ব্যবহার করেছি

এটি আমার কোডটি সাবক্লাসফ্লোলয়আউট: ক্লাসে রেখেছি

let padding: CGFloat = 16
override init() {
    super.init()
    self.minimumLineSpacing = padding
    self.minimumInteritemSpacing = 2
    self.scrollDirection = .horizontal
    self.sectionInset = UIEdgeInsets(top: 0, left: padding, bottom: 0, right: 100) //right = "should set for footer" (Horizental)

}

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

override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
    var offsetAdjustment = CGFloat.greatestFiniteMagnitude
    let leftInset = padding
    let horizontalOffset = proposedContentOffset.x + leftInset // leftInset is for "where you want the item stop on the left"
    let targetRect = CGRect(origin: CGPoint(x: proposedContentOffset.x, y: 0), size: self.collectionView!.bounds.size)

    for layoutAttributes in super.layoutAttributesForElements(in: targetRect)! {
        let itemOffset = layoutAttributes.frame.origin.x
        if (abs(itemOffset - horizontalOffset) < abs(offsetAdjustment)) {
            offsetAdjustment = itemOffset - horizontalOffset
        }
    }

    let targetPoint = CGPoint(x: proposedContentOffset.x + offsetAdjustment, y: proposedContentOffset.y)
    return targetPoint

}

সাবক্লাসিংয়ের পরে, ভিউডিডডলয়েড () এ এটি স্থাপন করা নিশ্চিত করুন:

customCollectionView.collectionViewLayout = SubclassFlowLayout()
customCollectionView.isPagingEnabled = false
customCollectionView.decelerationRate = .fast //-> this for scrollView speed

0

যারা সুইফটে সমাধান খুঁজছেন তাদের জন্য:

class CustomCollectionViewFlowLayout: UICollectionViewFlowLayout {
    private let collectionViewHeight: CGFloat = 200.0
    private let screenWidth: CGFloat = UIScreen.mainScreen().bounds.width

    override func awakeFromNib() {
        super.awakeFromNib()

        self.itemSize = CGSize(width: [InsertItemWidthHere], height: [InsertItemHeightHere])
        self.minimumInteritemSpacing = [InsertItemSpacingHere]
        self.scrollDirection = .Horizontal
        let inset = (self.screenWidth - CGFloat(self.itemSize.width)) / 2
        self.collectionView?.contentInset = UIEdgeInsets(top: 0,
                                                         left: inset,
                                                         bottom: 0,
                                                         right: inset)
    }

    override func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
        var offsetAdjustment = CGFloat.max
        let horizontalOffset = proposedContentOffset.x + ((self.screenWidth - self.itemSize.width) / 2)

        let targetRect = CGRect(x: proposedContentOffset.x, y: 0, width: self.screenWidth, height: self.collectionViewHeight)
        var array = super.layoutAttributesForElementsInRect(targetRect)

        for layoutAttributes in array! {
            let itemOffset = layoutAttributes.frame.origin.x
            if (abs(itemOffset - horizontalOffset) < abs(offsetAdjustment)) {
                offsetAdjustment = itemOffset - horizontalOffset
            }
        }

        return CGPoint(x: proposedContentOffset.x + offsetAdjustment, y: proposedContentOffset.y)
    }
}

-1

সেল দ্বারা পেজিংয়ের জন্য এখানে একটি ডেমো রয়েছে fast যখন দ্রুত স্ক্রোল করে, এক বা একাধিক কক্ষটি এড়িয়ে যান না): https://github.com/ApesTalk/ATPasingByCell

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