মোবাইল সাফারি ট্যাবগুলির মতো ইউআইএসক্রোলভিউ অনুভূমিক পেজিং


88

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

আমি এই নির্দিষ্ট আচরণটির প্রতিলিপি তৈরির চেষ্টা করছি যেখানে একটি অনুভূমিকভাবে স্ক্রোলযোগ্য ইউআইএসক্রোলভিউ পরবর্তী দর্শনের কিছু সামগ্রী দেখায়।

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

মোবাইল সাফারির মতো পরবর্তী ভিউর কিছু সামগ্রী দেখতে আমি কীভাবে একটি ইউআইএসক্রলভিউ পাই?


4
কেবল একটি চিন্তা ... স্ক্রোলের চেয়ে স্ক্রোল দেখার সীমানাকে আরও ছোট করে দেখুন এবং দেখুনগুলি সঠিকভাবে প্রদর্শন করার জন্য চারপাশে ঝাঁকুনি দিন। (এবং স্ক্রোল ভিউয়ের ক্লিপগুলি বিন্যাসে সেট করুন)
মেজয়

আমি ইউস্ক্রলভিউয়ের প্রস্থ (অনুভূমিক স্ক্রোল) এর চেয়ে বড় পৃষ্ঠাগুলি রাখতে চাই। এবং মিঃয়ের চিন্তাভাবনা আসলে আমাকে সাহায্য করেছিল!
সাশো

উত্তর:


263

একটি UIScrollViewসক্রিয় পেজিং সঙ্গে তার ফ্রেম প্রস্থ (অথবা উচ্চতা) এর গুণিতক থামবে। সুতরাং প্রথম পদক্ষেপটি আপনার পৃষ্ঠাগুলি কত প্রশস্ত হতে চান তা নির্ধারণ করা to এর প্রস্থটি তৈরি করুন UIScrollView। তারপরে, আপনার সাবউভিউয়ের আকারগুলি যত বড় হতে পারে সেগুলি সেট করুন এবং সেগুলির কেন্দ্রগুলির দৈর্ঘ্যের প্রস্থের বহুগুণের ভিত্তিতে সেট করুন UIScrollView

তারপরে, যেহেতু আপনি অন্যান্য পৃষ্ঠাগুলি অবশ্যই দেখতে চান, যেমনটি মুহজয়ীর বক্তব্য অনুযায়ী সেট করা clipsToBoundsআছে NO। কৌতুক অংশটি এখন এটি স্ক্রোল করতে পাচ্ছে যখন ব্যবহারকারী যখন UIScrollViewএর ফ্রেমের সীমার বাইরে টানা শুরু করে । আমার সমাধান (যখন আমাকে খুব সম্প্রতি এটি করতে হয়েছিল) নীচে ছিল:

একটি UIViewসাবক্লাস (যেমন ClipView) তৈরি করুন যাতে এতে UIScrollViewএবং এর সাবউভিউ থাকবে। মূলত, এটি UIScrollViewসাধারণ পরিস্থিতিতে আপনার কী হবে তা ধরে নেওয়ার ফ্রেম থাকা উচিত । UIScrollViewএর মাঝখানে রাখুন ClipView। নিশ্চিত করুন ClipView'র clipsToBoundsসেট করা হয় YESযদি তার প্রস্থ তার পিতা বা মাতা দৃশ্য যে এর চেয়ে কম। এছাড়াও, ClipViewপ্রয়োজনগুলির একটি রেফারেন্স প্রয়োজন UIScrollView

চূড়ান্ত পদক্ষেপটি এর - (UIView *)hitTest:withEvent:ভিতরে ওভাররাইড করা ClipView

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
  return [self pointInside:point withEvent:event] ? scrollView : nil;
}

এটি মূলত UIScrollViewএর পিতামাতার দেখার ফ্রেমের স্পর্শ অঞ্চলটি প্রসারিত করে , আপনার ঠিক কী প্রয়োজন।

আরেকটি বিকল্প হ'ল সাবক্লাস UIScrollViewএবং এর - (BOOL)pointInside:(CGPoint) point withEvent:(UIEvent *) eventপদ্ধতিটি ওভাররাইড করা হবে তবে ক্লিপিং করার জন্য আপনার এখনও একটি ধারক দৃশ্যের প্রয়োজন হবে এবং YESকেবলমাত্র UIScrollViewফ্রেমের উপর ভিত্তি করে কখন ফিরে আসবেন তা নির্ধারণ করা কঠিন হতে পারে ।

দ্রষ্টব্য: আপনার জুড়ি পাকাস্তে হিট টেস্ট: উইথ এভেন্ট: সংশোধন করা উচিত যদি আপনার সাবউভিউ ব্যবহারকারী ইন্টারঅ্যাকশন নিয়ে সমস্যা হয় having


4
ধন্যবাদ এড। আমি UIScrollViewদৃশ্যের অলস লোডিংয়ের জন্য একটি সাবক্লাস নিয়েছিলাম (ইন layoutSubviews), এবং পরীক্ষার clippingRectজন্য একটি ব্যবহার করেছি pointInside:withEvent:। সত্যই ভাল কাজ করে, এবং কোনও অতিরিক্ত ধারক দেখার প্রয়োজন নেই।
ওহোরব

4
দুর্দান্ত উত্তর। আমি UIScrollView@ হোরোব এর মতো একটি সাবক্লাস ব্যবহার করেছি তবে ক্লিপিং এবং ফিরে আসার জন্য ধারক দৃশ্যের [super pointInside:CGPointMake(self.contentOffset.x + self.frame.size.width/2, self.contentOffset.y + self.frame.size.height/2) withEvent:event];সাথে pointInside:withEvent:। এটি খুব ভালভাবে কাজ করে এবং @ জুড়িপাকাস্টের উত্তরে উল্লিখিত ব্যবহারকারীর মিথস্ক্রিয়া নিয়ে কোনও সমস্যা নেই।
কডাক

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

8
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffsetএইগুলি জুড়ে আসা লোকেরা সম্প্রতি সচেতন হন যা আইওএস 5 এর ইউআইএসক্রোলভিউ ডেলেগেটে যুক্ত হয়েছে এর অর্থ আপনাকে আর এই প্যালেভারটি অতিক্রম করতে হবে না।
মাইক পোলার্ড

4
@ মাইকপোলার্ড এর প্রভাবটি একরকম শান্ত নয়, টার্গেটকন্টেন্টএফসেট এই পরিস্থিতির সাথে ভাল মানায় না।
কাইল ফ্যাং

70

ClipViewসমাধান উপরে আমার জন্য কাজ, কিন্তু আমি একটি ভিন্ন কি ছিল-[UIView hitTest:withEvent:] বাস্তবায়ন। এড মার্টির সংস্করণটি অনুভূমিক স্ক্রোলভিউতে আমার অনুভূমিকের অভ্যন্তরে উল্লিখিত স্ক্রোলভিউগুলির সাথে ব্যবহার করে ব্যবহারকারীর ইন্টারঅ্যাকশনটি পায় নি।

নিম্নলিখিত সংস্করণটি আমার পক্ষে কাজ করেছে:

-(UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event
{
    UIView* child = nil;
    if ((child = [super hitTest:point withEvent:event]) == self)
        return self.scrollView;     
    return child;
}

এটি ব্যবহারকারীর মিথস্ক্রিয়া কর্মের সাথে বোতাম এবং অন্যান্য সাবভিউগুলি পেতে সহায়তা করে। :) ধন্যবাদ
থমাস ক্লেসন

4
এই কোডটির জন্য আপনাকে ধন্যবাদ, আমি স্ক্রোলভিউ সীমানায় না থাকা সাবভিউ (বোতাম) থেকে ইভেন্টগুলি পেতে এই পরিবর্তনটি কীভাবে ব্যবহার করতে পারি? এটি কাজ করে যদি উদাহরণস্বরূপ কোনও বোতামটি কেন্দ্রীয় স্ক্রোলভিউয়ের সীমানার মধ্যে থাকে তবে বাইরে নয়।
ড্রিমঅফমিয়ার্স

4
এটি সত্যিই সাহায্য করেছে। এটি নির্বাচিত উত্তরের একটি পরিবর্তন হিসাবে অন্তর্ভুক্ত করা উচিত।
পাকু

4
হ্যাঁ! এটি আবার স্ক্রোলভিউয়ের মধ্যে ব্যবহারকারীর ইন্টারঅ্যাকশনটিকেও কাজ করে তোলে! এটির কাজ করার জন্য আমাকে ক্লিপভিউতে ইউজার-ইন্টেরাকশনএইবল সক্ষম করে রাখতে হয়েছিল।
টম ভ্যান জুম্মেরেন

আমাকে সেলফ.স্ক্রোলভিউ.সুবভিউগুলির মাধ্যমে পুনরাবৃত্তি করতে হয়েছিল এবং প্রথমে হিটটেষ্ট সম্পাদন করতে হয়েছিল।
বাও লেই

8

আপনার পৃষ্ঠাগুলির আকার হ'ল স্ক্রোলভিউর ফ্রেম আকার সেট করুন:

[self.view addSubview:scrollView];
[self.view addGestureRecognizer:mainScrollView.panGestureRecognizer];

এখন আপনি প্যান করতে পারেন self.view, এবং স্ক্রোলভিউতে থাকা সামগ্রী স্ক্রোল করা হবে। সামগ্রীটি ক্লিপিং প্রতিরোধ করতে
ব্যবহার করুন scrollView.clipsToBounds = NO;


5

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

একটি শ্রেণি কাস্টমস্ক্রোলভিউ এবং সাবক্লাস ইউআইএসক্রোলভিউ তৈরি করুন। তারপরে আপনার যা করার দরকার তা হ'ল। মি ফাইলটিতে যুক্ত করুন:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
  return (point.y >= 0 && point.y <= self.frame.size.height);
}

এটি আপনাকে পাশ থেকে পাশের দিকে (আনুভূমিক) স্ক্রোল করতে দেয়। আপনার সোয়াইপ / স্ক্রোলিং টাচ অঞ্চল সেট করতে সীমানাটি ঠিকঠাক করুন। উপভোগ করুন!


4

আমি আরেকটি বাস্তবায়ন করেছি যা স্ক্রোলভিউটি স্বয়ংক্রিয়ভাবে ফিরে আসতে পারে। সুতরাং এটির আইবিআউটলেট থাকার দরকার নেই যা প্রকল্পে পুনরায় ব্যবহার সীমাবদ্ধ করবে।

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    if ([self pointInside:point withEvent:event]) {
        for (id view in [self subviews]) {
            if ([view isKindOfClass:[UIScrollView class]]) {
                return view;
            }
        }
    }
    return nil;
}

4
আপনার যদি ইতিমধ্যে একটি এক্সিব / স্টোরিবোর্ড থাকে তবে এটি ব্যবহার করতে পারেন। অন্যথায় আমি নিশ্চিত না যে আপনি কীভাবে পেজিং / স্ক্রোলভিউয়ের রেফারেন্স পাবেন। কোন ধারনা?
এমএসকেডব্লু

3

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

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    if (([self pointInside:point withEvent:event]) && (self.subviews.count >= 1))
    {
        // An extended-hit view should only have one sub-view, or make sure the
        // first subview is the one you want to expand the hit test for.
        return [self.subviews objectAtIndex:0];
    }

    return nil;
}

3

আমি উপরে বর্ণিত পরামর্শটি বাস্তবায়ন করেছি, তবে UICollectionViewআমি ফ্রেম থেকে বাইরে বিবেচিত কিছু ব্যবহার করছিলাম না screen এটি যখন ব্যবহারকারী তাদের দিকে স্ক্রোল করছিল তখন কাছাকাছি ঘরগুলি কেবল সীমার বাইরে রেন্ডার করে দেয়, যা আদর্শ ছিল না।

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

- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
{    
  if (velocity.x > 0) {
    proposedContentOffset.x = ceilf(self.collectionView.contentOffset.x / pageSize) * pageSize;
  }
  else {
    proposedContentOffset.x = floorf(self.collectionView.contentOffset.x / pageSize) * pageSize;
  }

  return proposedContentOffset;
}

এটি পুরোপুরি সোয়াইপ কর্মের প্রতিনিধিটিকে এড়িয়ে চলে, এটিও বোনাস ছিল। এর UIScrollViewDelegateমতো একটি অনুরূপ পদ্ধতি রয়েছে scrollViewWillEndDragging:withVelocity:targetContentOffset:যা ইউআইটিএবলভিউ এবং ইউআইএসক্রোলভিউ পৃষ্ঠাতে ব্যবহৃত হতে পারে।


4
ডেভ, আমি ইউআইসিকলিকেশনভিউটি ব্যবহার করেও এমন আচরণ অর্জনের জন্য লড়াই করে যাচ্ছিলাম এবং আপনি এখানে বর্ণিত একই পদ্ধতির ব্যবহারটি শেষ করেছিলাম। তবে স্ক্রলিংয়ের অভিজ্ঞতাটি ততটা ভাল নয় যেমন এটি পেজিং সক্ষম করে দেওয়া একটি স্ক্রোলভিউ ছিল। আমি যখন বড় গতিতে পরিবর্তন করেছিলাম তখন বেশ কয়েকটি পৃষ্ঠাগুলি স্ক্রোল করা হয়েছিল এবং এটি প্রস্তাবিত পৃষ্ঠায় বন্ধ হয়ে গেছে। আমি যা অর্জন করতে চাই তা হ'ল পেজিং সক্ষম থাকা সহ সাধারণ স্ক্রোল ভিউ হিসাবে আচরণ সংরক্ষণ করা - আমি যত বেগ ব্যবহার করি না কেন আমি আরও 1 টি পৃষ্ঠা পেতে পারি will কীভাবে এটি করবেন আপনার কোনও ধারণা আছে?
পিটার স্ট্যাজার

3

এই এসও প্রশ্নের কৌশলটি সমর্থন করার সময় স্ক্রোল ভিউয়ের চাইল্ড ভিউগুলিতে ট্যাপ ইভেন্টগুলি ফায়ারিং সক্ষম করুন। পঠনযোগ্যতার জন্য স্ক্রোল ভিউ (স্ব। স্ক্রোলভিউ) এর একটি উল্লেখ উল্লেখ করে।

- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    UIView *hitView = nil;
    NSArray *childViews = [self.scrollView subviews];
    for (NSUInteger i = 0; i < childViews.count; i++) {
        CGRect childFrame = [[childViews objectAtIndex:i] frame];
        CGRect scrollFrame = self.scrollView.frame;
        CGPoint contentOffset = self.scrollView.contentOffset;
        if (childFrame.origin.x + scrollFrame.origin.x < point.x + contentOffset.x &&
            point.x + contentOffset.x < childFrame.origin.x + scrollFrame.origin.x + childFrame.size.width &&
            childFrame.origin.y + scrollFrame.origin.y < point.y + contentOffset.y &&
            point.y + contentOffset.y < childFrame.origin.y + scrollFrame.origin.y + childFrame.size.height
        ){
            hitView = [childViews objectAtIndex:i];
            return hitView;
        }
    }
    hitView = [super hitTest:point withEvent:event];
    if (hitView == self)
        return self.scrollView;
    return hitView;
}

স্পর্শ ইভেন্টটি ক্যাপচার করতে এটি আপনার শিশু দর্শনে যুক্ত করুন:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

(এটি ব্যবহারকারীর 1856273 এর সমাধানে পরিবর্তিত read


সাবউউয়ে এম্বেড থাকা কোনও ইউআইবাটনটিতে কাজ করতে আলতো চাপতে, আমি কোডটি হিটভিউ = [চাইল্ডভিউজ অবজেক্টঅটিআইডেক্স: i] প্রতিস্থাপন করেছি; // এর সাথে ইউআইবাটনটি সন্ধান করুন (ইউআইভিউ * প্যানভিউতে [[চাইল্ডভিউজ অবজেক্টটিআইটিআইডেক্স: i] সাবভিউ]]) {যদি ([পেনভিউ isKindOfClass: [UIButton শ্রেণি]]) পেনভিউ রিটার্ন করুন; }
চার্লসএ

2

আমার সংস্করণটি স্ক্রলটিতে থাকা বোতাম টিপছে - work =)

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    UIView* child = nil;
    for (int i=0; i<[[[[self subviews] objectAtIndex:0] subviews] count];i++) {

        CGRect myframe =[[[[[self subviews] objectAtIndex:0] subviews]objectAtIndex:i] frame];
        CGRect myframeS =[[[self subviews] objectAtIndex:0] frame];
        CGPoint myscroll =[[[self subviews] objectAtIndex:0] contentOffset];
        if (myframe.origin.x < point.x && point.x < myframe.origin.x+myframe.size.width &&
            myframe.origin.y+myframeS.origin.y < point.y+myscroll.y && point.y+myscroll.y < myframe.origin.y+myframeS.origin.y +myframe.size.height){
            child = [[[[self subviews] objectAtIndex:0] subviews]objectAtIndex:i];
            return child;
        }


    }

    child = [super hitTest:point withEvent:event];
    if (child == self)
        return [[self subviews] objectAtIndex:0];
    return child;
    }

তবে কেবলমাত্র [[স্ব সাবউভিউস] অবজেক্টআটিআইডেক্স: 0] অবশ্যই একটি স্ক্রোল হতে হবে


এটি আমার সমস্যার সমাধান করেছে :) কেবল লক্ষ্য করুন যে আপনি যখন সীমানা পরীক্ষা করছেন তখন আপনি স্ক্রলটি পয়েন্ট.এক্সে অফসেট করছেন না এবং এর ফলে কোডটি অনুভূমিক স্ক্রোলগুলিতে ভাল কাজ করে না। যোগ করার পরে, এটি ঠিক কাজ করেছে!
বার্টসার্ক

2

এখানে এড মার্টির উত্তরের উপর ভিত্তি করে একটি সুইফ্ট উত্তর দেওয়া হয়েছে তবে স্ক্রোলভিউয়ের ভিতরে বোতামে ট্যাপ ইত্যাদির অনুমতি দেওয়ার জন্য জুড়ি পাকাস্তে সংশোধনও করেছেন।

override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
    let view = super.hitTest(point, with: event)
    return view == self ? scrollView : view
}

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