ফ্রেম আকারের চেয়ে ছোট ইনক্রিমেন্টগুলিতে ইউআইএসক্রোলভিউকে পেজিং করা হচ্ছে


87

আমার কাছে একটি স্ক্রোল ভিউ রয়েছে যা পর্দার প্রস্থ তবে প্রায় 70 পিক্সেল উচ্চ। এটিতে অনেকগুলি 50 x 50 আইকন রয়েছে (তাদের চারপাশের স্থান সহ) যা আমি ব্যবহারকারী পছন্দ করতে চাই to তবে আমি সর্বদা চাই চাই যে স্ক্রোল ভিউটি একটি পেজযুক্ত পদ্ধতিতে আচরণ করা হোক, সর্বদা সঠিক কেন্দ্রে একটি আইকন রেখে থামান।

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

অলরেসিপস অ্যাপ্লিকেশন কল করার আগে আমি এই আচরণটি দেখেছি। আমি এটি জানি না।

আমি কীভাবে প্রতি আইকন আকারের কাজের জন্য পেজিং করব?

উত্তর:


123

আপনার স্ক্রোলভিউটি স্ক্রিনের আকারের চেয়ে কম (প্রস্থ অনুসারে) তৈরি করার চেষ্টা করুন, তবে আইবিতে "ক্লিপ সাবভিউগুলি" চেকবাক্সটি নির্বাচন করুন। তারপরে, একটি স্বচ্ছ, ব্যবহারকারীর পরিচয়প্রাপ্ত অক্ষম = এর শীর্ষে কোনও ভিউ নেই (পূর্ণ প্রস্থে) যা হিটটেষ্টকে ওভাররাইড করে: ইভেন্ট: আপনার স্ক্রোল ভিউটি ফিরিয়ে আনতে। এটি যা আপনি খুঁজছেন তা দেওয়া উচিত। আরও তথ্যের জন্য এই উত্তর দেখুন ।


4
আপনি কী বলতে চাইছেন তা সম্পর্কে আমি নিশ্চিত নই, আপনি যে উত্তরটি দেখিয়েছেন আমি সে দিকে তাকাব।
হেনিং

8
এটি একটি সুন্দর সমাধান। আমি হিটটেষ্টকে ওভাররাইড করার কথা ভাবিনি: ফাংশন এবং এই পদ্ধতির একমাত্র নেতিবাচকতা কেটে দেয়। সুন্দরভাবে সম্পন্ন.
বেন Gotow

চমৎকার সমাধান! সত্যিই আমাকে সাহায্য করেছে।
দেবদেবদেভ

8
এটি সত্যই ভাল কাজ করে, তবে আমি কেবল স্ক্রোলভিউটি ফিরিয়ে না দেওয়ার পরিবর্তে [স্ক্রোলভিউ হিটটেষ্ট: পয়েন্ট উইথ ওয়েভ: ইভেন্ট] এর পরিবর্তে প্রস্তাব দেব যাতে ইভেন্টগুলি যথাযথভাবে পাস হয় pass উদাহরণস্বরূপ, ইউআইবাটনগুলিতে পূর্ণ স্ক্রোল ভিউতে বোতামগুলি এখনও এইভাবে কাজ করবে।
গ্রিনিয়াস

4
দ্রষ্টব্য, এটি কোনও টেবিলভিউ বা সংগ্রহ ভিউয়ের সাথে কাজ করবে না কারণ এটি ফ্রেমের বাইরে জিনিসগুলি রেন্ডার করে না। আমার উত্তরটি নীচে দেখুন
বিশশ

63

এছাড়াও আরও একটি সমাধান রয়েছে যা আরও একটি ভিউ এবং ওভাররাইড হিটটেষ্টের সাহায্যে ওভারলেলিং স্ক্রোল ভিউয়ের চেয়ে কিছুটা ভাল।

আপনি ইউআইএসক্রোলভিউ সাবক্লাস করতে পারেন এবং এর পয়েন্টআইনসাইডকে ওভাররাইড করতে পারেন। তারপরে স্ক্রোল ভিউটি এর ফ্রেমের বাইরে ছোঁয়ার প্রতিক্রিয়া জানাতে পারে। বাকিটাও এক রকম।

@interface PagingScrollView : UIScrollView {

    UIEdgeInsets responseInsets;
}

@property (nonatomic, assign) UIEdgeInsets responseInsets;

@end


@implementation PagingScrollView

@synthesize responseInsets;

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    CGPoint parentLocation = [self convertPoint:point toView:[self superview]];
    CGRect responseRect = self.frame;
    responseRect.origin.x -= responseInsets.left;
    responseRect.origin.y -= responseInsets.top;
    responseRect.size.width += (responseInsets.left + responseInsets.right);
    responseRect.size.height += (responseInsets.top + responseInsets.bottom);

    return CGRectContainsPoint(responseRect, parentLocation);
}

@end

4
হ্যাঁ! তদ্ব্যতীত, যদি আপনার স্ক্রোলভিউয়ের সীমানা তার পিতামাতার সাথে একই হয় তবে আপনি কেবল পয়েন্টইনসাইড পদ্ধতি থেকে হ্যাঁ ফিরতে পারেন। ধন্যবাদ
কোকোচৌচার

4
আমি এই সমাধানটি পছন্দ করি, যদিও এটি সঠিকভাবে কাজ করার জন্য আমাকে প্যারেন্টলোকেশনকে "[স্ব রূপান্তর পয়েন্ট: পয়েন্ট টুভিউ: স্ব.সুপারভিউ]] তে পরিবর্তন করতে হবে।
amrox

আপনারা ঠিক বলেছেন কনভার্টপয়েন্ট আমার লেখার চেয়ে অনেক ভাল।
স্প্লিট

6
সরাসরি return [self.superview pointInside:[self convertPoint:point toView:self.superview] withEvent:event];@ ইম্রাক্স @ স্প্লিট আপনার প্রতিক্রিয়া লাগবে না যদি আপনার কাছে এমন একটি সুপারভিউ থাকে যা ক্লিপিং ভিউ হিসাবে কাজ করে।
সিউর

আইটেমের শেষ পৃষ্ঠাটি সম্পূর্ণরূপে পৃষ্ঠাটি পূরণ না করে যদি এই আইটেমের তালিকাটি শেষ হয় তখন এই সমাধানটি ভেঙে গেছে বলে মনে হচ্ছে। এটি বোঝাতে একরকম কঠিন, তবে আমি যদি প্রতি পৃষ্ঠায় ৩.৫ টি সেল দেখায় এবং আমার কাছে 5 টি আইটেম থাকে তবে দ্বিতীয় পৃষ্ঠায় হয় আমাকে ডানদিকে ফাঁকা স্থান সহ 2 টি সেল দেখায়, অথবা এটি একটি শীর্ষস্থানীয় 3 টি ঘর দেখায় আংশিক ঘর সমস্যাটি হ'ল যদি আমি সেই রাজ্যে থাকি যেখানে এটি আমাকে খালি জায়গা দেখায় এবং আমি একটি ঘর নির্বাচন করি তবে পেজিংটি ন্যাভ ট্রানজিশনের সময় নিজেকে সংশোধন করবে ... আমি আমার সমাধানটি নীচে পোস্ট করব।
টাইলার

18

আমি অনেকগুলি সমাধান দেখি, তবে সেগুলি খুব জটিল। ছোট পৃষ্ঠাগুলি রাখার একটি সহজ উপায় তবে এখনও সমস্ত অঞ্চল স্ক্রোলযোগ্য রাখার জন্য, স্ক্রোলটি আরও ছোট করা এবং scrollView.panGestureRecognizerআপনার পিতামাতার দৃশ্যে স্থানান্তরিত করা । এই পদক্ষেপগুলি:

  1. আপনার স্ক্রোলভিউ আকার হ্রাস করুনস্ক্রোলভিউয়ের আকার পিতামাতার চেয়ে ছোট

  2. আপনার স্ক্রোল ভিউ পৃষ্ঠাভুক্ত এবং সাবভিউ ক্লিপ না করে তা নিশ্চিত করুন এখানে চিত্র বর্ণনা লিখুন

  3. কোডে, স্ক্রোলভিউ প্যান অঙ্গভঙ্গিটি পূর্ণ প্রস্থের প্যারেন্ট কনটেয়ার ভিউতে সরান:

    override func viewDidLoad() {
        super.viewDidLoad()
        statsView.addGestureRecognizer(statsScrollView.panGestureRecognizer)
    }

এটি একটি গ্রীয়িয়েট সমাধান। খুব সুদর্শন.
মেটেপুক

এটাই আসলে আমি চাই!
এলওয়াইএম

খুব সুদর্শন! তুমি আমাকে ঘন্টা বাঁচিয়েছ ধন্যবাদ!
এরিক

6

গৃহীত উত্তরটি খুব ভাল তবে এটি কেবল UIScrollViewশ্রেণীর পক্ষে কাজ করবে এবং এর বংশধরদের মধ্যে কেউই থাকবে না। উদাহরণস্বরূপ, যদি আপনার প্রচুর মতামত থাকে এবং একটিতে রূপান্তর করেন তবে আপনি UICollectionViewএই পদ্ধতিটি ব্যবহার করতে পারবেন না, কারণ সংগ্রহ ভিউটি এমন দৃশ্যগুলি সরিয়ে ফেলবে যা মনে করে যে এটি "দৃশ্যমান নয়" (তাই তারা ক্লিপড না হওয়া সত্ত্বেও) অদৃশ্য হয়ে যাওয়া)।

যে উল্লেখ সম্পর্কে মন্তব্যটি scrollViewWillEndDragging:withVelocity:targetContentOffset:আমার মতে, সঠিক উত্তর।

আপনি যা করতে পারেন তা হল এই প্রতিনিধি পদ্ধতির অভ্যন্তরে আপনি বর্তমান পৃষ্ঠা / সূচি গণনা করুন। তারপরে আপনি সিদ্ধান্ত নেবেন যে বেগ এবং টার্গেট অফসেটের জন্য "পরের পৃষ্ঠা" আন্দোলনের যোগ্যতা অর্জন করবে কিনা। আপনি pagingEnabledআচরণের কাছাকাছি যেতে পারেন ।

দ্রষ্টব্য: আমি আজকাল সাধারণত একটি রুবিমোশন দেব, সুতরাং কেউ দয়া করে সঠিকতার জন্য এই ওজ-সি কোডটি প্রমাণ করুন। উট কেস এবং সাপ_কেসের মিশ্রণের জন্য দুঃখিত, আমি এই কোডটির অনেকগুলি অনুলিপি করে আটকিয়েছি।

- (void) scrollViewWillEndDragging:(UIScrollView *)scrollView
         withVelocity:(CGPoint)velocity
         targetContentOffset:(inout CGPoint *)targetOffset
{
    CGFloat x = targetOffset->x;
    int index = [self convertXToIndex: x];
    CGFloat w = 300f;  // this is your custom page width
    CGFloat current_x = w * [self convertXToIndex: scrollView.contentOffset.x];

    // even if the velocity is low, if the offset is more than 50% past the halfway
    // point, proceed to the next item.
    if ( velocity.x < -0.5 || (current_x - x) > w / 2 ) {
      index -= 1
    } 
    else if ( velocity.x > 0.5 || (x - current_x) > w / 2 ) {
      index += 1;
    }

    if ( index >= 0 || index < self.items.length ) {
      CGFloat new_x = [self convertIndexToX: index];
      targetOffset->x = new_x;
    }
} 

হা হা এখন আমি ভাবছি যদি আমি রুবিমোশনটির কথা না বলে থাকি - তবে এটি আমাকে নিম্নমানের করে দিচ্ছে! না আসলে আমি ইচ্ছা করি ডাউনভোটদেরও কিছু মন্তব্য অন্তর্ভুক্ত ছিল, আমি আমার ব্যাখ্যাতে লোকেরা কী ভুল বুঝতে পারে তা জানতে আগ্রহী।
কলিনতা

আপনি convertXToIndex:এবং জন্য সংজ্ঞা অন্তর্ভুক্ত করতে পারেন convertIndexToX:?
এমআর 5

অসম্পূর্ণ. আপনি যখন আস্তে আস্তে টেনে আনুন এবং আপনার হাতটি velocityশূন্যের সাথে তুলবেন, তখন তা ফিরে আসবে, যা আশ্চর্যের। সুতরাং আমি আরও ভাল উত্তর আছে।
ডনসং

4
- (void) scrollViewWillEndDragging:(UIScrollView *)scrollView
         withVelocity:(CGPoint)velocity
         targetContentOffset:(inout CGPoint *)targetOffset
{
    static CGFloat previousIndex;
    CGFloat x = targetOffset->x + kPageOffset;
    int index = (x + kPageWidth/2)/kPageWidth;
    if(index<previousIndex - 1){
        index = previousIndex - 1;
    }else if(index > previousIndex + 1){
        index = previousIndex + 1;
    }

    CGFloat newTarget = index * kPageWidth;
    targetOffset->x = newTarget - kPageOffset;
    previousIndex = index;
} 

কেপেজউইডথ হ'ল প্রস্থ যা আপনি নিজের পৃষ্ঠায় চান want কেপেজঅফসেটটি হ'ল যদি আপনি না চান যে ঘরগুলি প্রান্তিককরণ করা যায় (যেমন আপনি যদি সেগুলি কেন্দ্রের সাথে যুক্ত করতে চান তবে এটি আপনার ঘরের অর্ধেক প্রস্থে সেট করুন)। অন্যথায়, এটি শূন্য হওয়া উচিত।

এটি একবারে কেবল একটি পৃষ্ঠা স্ক্রোল করার অনুমতি দেবে।


3

-scrollView:didEndDragging:willDecelerate:পদ্ধতিটি একবার দেখুন UIScrollViewDelegate। কিছুটা এইরকম:

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
    int x = scrollView.contentOffset.x;
    int xOff = x % 50;
    if(xOff < 25)
        x -= xOff;
    else
        x += 50 - xOff;

    int halfW = scrollView.contentSize.width / 2; // the width of the whole content view, not just the scroll view
    if(x > halfW)
        x = halfW;

    [scrollView setContentOffset:CGPointMake(x,scrollView.contentOffset.y)];
}

এটি নিখুঁত নয় - সর্বশেষে আমি এই কোডটি চেষ্টা করেছিলাম যখন রাবার-ব্যান্ডযুক্ত স্ক্রোল থেকে ফিরে আসার সময় আমি কিছু কুৎসিত আচরণ পেয়েছিলাম (লাফিয়ে লাফানো, যেমন আমি মনে করি)। আপনি কেবল এটিকে এড়াতে সক্ষম হবেন কেবলমাত্র স্ক্রোল ভিউয়ের bouncesসম্পত্তি এতে সেট করে NO


3

যেহেতু এখনও আমাকে মন্তব্য করার অনুমতি দেওয়া হয়নি বলে মনে হচ্ছে আমি নোহের উত্তর এখানে আমার মন্তব্য যুক্ত করব add

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

         - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
         {      
             // Don't snap when at the edges because that will override the bounce mechanic
             if (self.contentOffset.x < 0 || self.contentOffset.x + self.bounds.size.width > self.contentSize.width)
                 return;

             ...
         }

আমি আরও জানতে পেরেছিলাম যে সমস্ত ক্ষেত্রে আমাকে ধরার জন্য -scrollViewWillBeginDecelerating:পদ্ধতিটি প্রয়োগ করতে UIScrollViewDelegateহবে।


অতিরিক্ত কোন মামলা ধরা দরকার?
ক্রিশ

কেস যেখানে কোনও টানছিল না। ব্যবহারকারী আঙুলটি তুলে নিয়ে যায় এবং ততক্ষণে স্ক্রোলিং বন্ধ হয়।
জেস বোয়ার্স 21

3

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


0

স্ক্রোলভিউ তৈরি করার সময়, আপনি এটি সেট করেছেন তা নিশ্চিত করুন:

scrollView.showsHorizontalScrollIndicator = false;
scrollView.showsVerticalScrollIndicator = false;
scrollView.pagingEnabled = true;

তারপরে স্ক্রোলারের সাথে আপনার সাবভিউগুলি স্ক্রোলারের সূচক * উচ্চতার সমান অফসেটে যুক্ত করুন। এটি একটি উল্লম্ব স্ক্রোলারের জন্য:

UIView * sub = [UIView new];
sub.frame = CGRectMake(0, index * h, w, subViewHeight);
[scrollView addSubview:sub];

আপনি যদি এটি চালান এখনই দর্শনগুলি ফাঁক হয়ে গেছে, এবং পেজিং সক্ষম করার সাথে তারা একবারে একটিতে স্ক্রোল করে।

সুতরাং এটি আপনার ভিউডিডস্ক্রোল পদ্ধতিতে রাখুন:

    //set vars
    int index = scrollView.contentOffset.y / h; //current index
    float y = scrollView.contentOffset.y; //actual offset
    float p = (y / h)-index; //percentage of page scroll complete (0.0-1.0)
    int subViewHeight = h-240; //height of the view
    int spacing = 30; //preferred spacing between views (if any)

    NSArray * array = scrollView.subviews;

    //cycle through array
    for (UIView * sub in array){

        //subview index in array
        int subIndex = (int)[array indexOfObject:sub];

        //moves the subs up to the top (on top of each other)
        float transform = (-h * subIndex);

        //moves them back down with spacing
        transform += (subViewHeight + spacing) * subIndex;

        //adjusts the offset during scroll
        transform += (h - subViewHeight - spacing) * p;

        //adjusts the offset for the index
        transform += index * (h - subViewHeight - spacing);

        //apply transform
        sub.transform = CGAffineTransformMakeTranslation(0, transform);
    }

সাবউভিউগুলির ফ্রেমগুলি এখনও ফাঁকা রয়েছে, আমরা কেবল তাদের ব্যবহারকারীর স্ক্রোল হিসাবে রূপান্তর মাধ্যমে একসাথে সরিয়ে নিচ্ছি।

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


0

স্ক্রোলভিউয়ের সামগ্রী অন্তর্ভুক্ত সম্পত্তি ব্যবহার করার চেষ্টা করুন:

scrollView.pagingEnabled = YES;

[scrollView setContentSize:CGSizeMake(height, pageWidth * 3)];
double leftContentOffset = pageWidth - kSomeOffset;
scrollView.contentInset = UIEdgeInsetsMake(0, leftContentOffset, 0, 0);

কাঙ্ক্ষিত পেজিংটি অর্জন করতে আপনার মানগুলি নিয়ে কিছুটা সময় নিতে পারে।

পোস্ট করা বিকল্পগুলির তুলনায় এটি আরও পরিষ্কারভাবে কাজ করতে আমি পেয়েছি। scrollViewWillEndDragging:প্রতিনিধি পদ্ধতি ব্যবহারে সমস্যা হ'ল ধীর ফ্লিক্সগুলির জন্য ত্বরণ স্বাভাবিক নয়।


0

এটিই সমস্যার একমাত্র আসল সমাধান।

import UIKit

class TestScrollViewController: UIViewController, UIScrollViewDelegate {

    var scrollView: UIScrollView!

    var cellSize:CGFloat!
    var inset:CGFloat!
    var preX:CGFloat=0
    let pages = 8

    override func viewDidLoad() {
        super.viewDidLoad()

        cellSize = (self.view.bounds.width-180)
        inset=(self.view.bounds.width-cellSize)/2
        scrollView=UIScrollView(frame: self.view.bounds)
        self.view.addSubview(scrollView)

        for i in 0..<pages {
            let v = UIView(frame: self.view.bounds)
            v.backgroundColor=UIColor(red: CGFloat(CGFloat(i)/CGFloat(pages)), green: CGFloat(1 - CGFloat(i)/CGFloat(pages)), blue: CGFloat(CGFloat(i)/CGFloat(pages)), alpha: 1)
            v.frame.origin.x=CGFloat(i)*cellSize
            v.frame.size.width=cellSize
            scrollView.addSubview(v)
        }

        scrollView.contentSize.width=cellSize*CGFloat(pages)
        scrollView.isPagingEnabled=false
        scrollView.delegate=self
        scrollView.contentInset.left=inset
        scrollView.contentOffset.x = -inset
        scrollView.contentInset.right=inset

    }

    func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
        preX = scrollView.contentOffset.x
    }

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

        let originalIndex = Int((preX+cellSize/2)/cellSize)

        let targetX = targetContentOffset.pointee.x
        var targetIndex = Int((targetX+cellSize/2)/cellSize)

        if targetIndex > originalIndex + 1 {
            targetIndex=originalIndex+1
        }
        if targetIndex < originalIndex - 1 {
            targetIndex=originalIndex - 1
        }

        if velocity.x == 0 {
            let currentIndex = Int((scrollView.contentOffset.x+self.view.bounds.width/2)/cellSize)
            let tx=CGFloat(currentIndex)*cellSize-(self.view.bounds.width-cellSize)/2
            scrollView.setContentOffset(CGPoint(x:tx,y:0), animated: true)
            return
        }

        let tx=CGFloat(targetIndex)*cellSize-(self.view.bounds.width-cellSize)/2
        targetContentOffset.pointee.x=scrollView.contentOffset.x

        UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: velocity.x, options: [UIViewAnimationOptions.curveEaseOut, UIViewAnimationOptions.allowUserInteraction], animations: {
            scrollView.contentOffset=CGPoint(x:tx,y:0)
        }) { (b:Bool) in

        }

    }


}

0

আমার উত্তর এখানে। আমার উদাহরণে, collectionViewযার একটি বিভাগ শিরোনাম রয়েছে তা হ'ল স্ক্রোলভিউ যা আমরা এটির কাস্টম isPagingEnabledপ্রভাব তৈরি করতে চাই এবং সেলটির উচ্চতা একটি ধ্রুবক মান।

var isScrollingDown = false // in my example, scrollDirection is vertical
var lastScrollOffset = CGPoint.zero

func scrollViewDidScroll(_ sv: UIScrollView) {
    isScrollingDown = sv.contentOffset.y > lastScrollOffset.y
    lastScrollOffset = sv.contentOffset
}

// 实现 isPagingEnabled 效果
func scrollViewWillEndDragging(_ sv: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {

    let realHeaderHeight = headerHeight + collectionViewLayout.sectionInset.top
    guard realHeaderHeight < targetContentOffset.pointee.y else {
        // make sure that user can scroll to make header visible.
        return // 否则无法手动滚到顶部
    }

    let realFooterHeight: CGFloat = 0
    let realCellHeight = cellHeight + collectionViewLayout.minimumLineSpacing
    guard targetContentOffset.pointee.y < sv.contentSize.height - realFooterHeight else {
        // make sure that user can scroll to make footer visible
        return // 若有footer,不在此处 return 会导致无法手动滚动到底部
    }

    let indexOfCell = (targetContentOffset.pointee.y - realHeaderHeight) / realCellHeight
    // velocity.y can be 0 when lifting your hand slowly
    let roundedIndex = isScrollingDown ? ceil(indexOfCell) : floor(indexOfCell) // 如果松手时滚动速度为 0,则 velocity.y == 0,且 sv.contentOffset == targetContentOffset.pointee
    let y = realHeaderHeight + realCellHeight * roundedIndex - collectionViewLayout.minimumLineSpacing
    targetContentOffset.pointee.y = y
}

0

UICollectionViewসমাধানটির পরিশোধিত সুইফ্ট সংস্করণ :

  • সোয়াইপ প্রতি এক পৃষ্ঠার সীমাবদ্ধ
  • আপনার স্ক্রোলটি ধীর হলেও গতিতে পৃষ্ঠায় দ্রুত স্ন্যাপ নিশ্চিত করে
override func viewDidLoad() {
    super.viewDidLoad()
    collectionView.decelerationRate = .fast
}

private var dragStartPage: CGPoint = .zero

func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
    dragStartOffset = scrollView.contentOffset
}

func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
    // Snap target offset to current or adjacent page
    let currentIndex = pageIndexForContentOffset(dragStartOffset)
    var targetIndex = pageIndexForContentOffset(targetContentOffset.pointee)
    if targetIndex != currentIndex {
        targetIndex = currentIndex + (targetIndex - currentIndex).signum()
    } else if abs(velocity.x) > 0.25 {
        targetIndex = currentIndex + (velocity.x > 0 ? 1 : 0)
    }
    // Constrain to valid indices
    if targetIndex < 0 { targetIndex = 0 }
    if targetIndex >= items.count { targetIndex = max(items.count-1, 0) }
    // Set new target offset
    targetContentOffset.pointee.x = contentOffsetForCardIndex(targetIndex)
}

0

পুরাতন থ্রেড, তবে এই বিষয়ে আমার গ্রহণযোগ্যতা উল্লেখযোগ্য:

import Foundation
import UIKit

class PaginatedCardScrollView: UIScrollView {

    convenience init() {
        self.init(frame: CGRect.zero)
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        _setup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        _setup()
    }

    private func _setup() {
        isPagingEnabled = true
        isScrollEnabled = true
        clipsToBounds = false
        showsHorizontalScrollIndicator = false
    }

    override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
        // Asume the scrollview extends uses the entire width of the screen
        return point.y >= frame.origin.y && point.y <= frame.origin.y + frame.size.height
    }
}

এইভাবে আপনি ক) প্যান / সোয়াইপ করতে স্ক্রোলভিউয়ের পুরো প্রস্থটি ব্যবহার করতে পারেন এবং খ) স্ক্রোলভিউয়ের মূল সীমানার বাইরে থাকা উপাদানগুলির সাথে ইন্টারঅ্যাক্ট করতে সক্ষম হবেন


0

ইউআইকোলিকেশনভিউ ইস্যুটির জন্য (যা আমার কাছে আসন্ন / পূর্ববর্তী কার্ডের "টিকারস" সহ অনুভূমিকভাবে স্ক্রোলিং কার্ডের সংগ্রহের একটি ইউআইটিএবলভিউসেল ছিল), কেবলমাত্র অ্যাপলের নেটিজ পেজিংটি ব্যবহার করা ছেড়ে দিতে হয়েছিল। ডেমিয়েন এর GitHub সমাধান আমার জন্য awesomely কাজ করেন। প্রথম সূচীতে যখন আপনি শিরোনামের প্রস্থকে শেষ না করেন তখন আপনি শিরোনামের প্রস্থকে উচ্চতর করে এবং গতিশীলভাবে এটি শূন্যের আকারের মাধ্যমে টিকলার আকারটি টুইঙ্ক করতে পারেন can

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