सवाल UIScrollView: क्षैतिज रूप से पेजिंग, लंबवत स्क्रॉलिंग?


मैं कैसे मजबूर कर सकता हूं UIScrollView जिसमें किसी पल में केवल लंबवत या क्षैतिज रूप से स्थानांतरित करने के लिए पेजिंग और स्क्रॉलिंग चल रही है?

मेरी समझ यह है कि directionalLockEnabled संपत्ति को यह प्राप्त करना चाहिए, लेकिन एक विकर्ण स्वाइप अभी भी एक अक्ष पर गति को सीमित करने के बजाय दृश्य को तिरछे स्क्रॉल करने का कारण बनता है।

संपादित करें: स्पष्ट होने के लिए, मैं उपयोगकर्ता को क्षैतिज या लंबवत स्क्रॉल करने की अनुमति देना चाहता हूं, लेकिन दोनों एक साथ नहीं।


79
2018-04-07 23:44


मूल


क्या आप केवल क्षितिज / वर्ट स्क्रॉल करने के लिए एक दृश्य को बाधित करना चाहते हैं या आप चाहते हैं कि उपयोगकर्ता होरिज़ या वर्ट स्क्रॉल करे, लेकिन दोनों एक साथ नहीं? - Will Hartung
क्या आप मुझे एक एहसान कर सकते हैं और शीर्षक बदल सकते हैं ताकि यह थोड़ा और दिलचस्प और गैर-तुच्छ दिख सके? कुछ "UIScrollView: क्षैतिज रूप से पेजिंग, लंबवत स्क्रॉलिंग?" - Andrey Tarantsov
दुर्भाग्यवश, मैंने इस प्रश्न को एक कंप्यूटर पर एक अपंजीकृत उपयोगकर्ता के रूप में पोस्ट किया है, जिसके पास अब तक पहुंच नहीं है (जब मैं घर आया था उसी नाम के तहत पंजीकरण करने से पहले), जिसका अर्थ है कि मैं इसे संपादित नहीं कर सकता। यह मुझे मूल प्रश्न को संपादित करने के बजाय नीचे-नीचे नीचे बताएगा। इस बार ढेर शिष्टाचार तोड़ने के लिए खेद है! - Nick


जवाब:


आप एक बहुत ही कठिन परिस्थिति में हैं, मुझे कहना होगा।

ध्यान दें कि आपको UIScrollView का उपयोग करने की आवश्यकता है pagingEnabled=YES पृष्ठों के बीच स्विच करने के लिए, लेकिन आपको चाहिए pagingEnabled=NO लंबवत स्क्रॉल करने के लिए।

2 संभावित रणनीतियों हैं। मुझे नहीं पता कि कौन सा काम करेगा / कार्यान्वित करना आसान है, इसलिए दोनों को आजमाएं।

प्रथम: नेस्टेड UIScrollViews। वाकई, मुझे अभी तक एक ऐसे व्यक्ति को देखना है जिसने इसे काम करने के लिए मिला है। हालांकि मैंने व्यक्तिगत रूप से काफी मेहनत की कोशिश नहीं की है, और मेरा अभ्यास दिखाता है कि जब आप काफी मेहनत करते हैं, तो आप कर सकते हैं UIScrollView को जो कुछ भी आप चाहते हैं उसे करें

तो रणनीति बाहरी स्क्रॉल दृश्य को केवल क्षैतिज स्क्रॉलिंग को संभालने देना है, और आंतरिक स्क्रॉल दृश्य केवल लंबवत स्क्रॉलिंग को संभालने के लिए है। इसे पूरा करने के लिए, आपको पता होना चाहिए कि UIScrollView आंतरिक रूप से कैसे काम करता है। यह ओवरराइड करता है hitTest विधि और हमेशा खुद को लौटता है, ताकि सभी स्पर्श घटनाएं UIScrollView में जाएं। फिर अंदर touchesBegan, touchesMoved आदि यह जांचता है कि क्या यह घटना में रूचि रखता है, और या तो इसे आंतरिक घटकों पर संभालता है या पास करता है।

यह तय करने के लिए कि स्पर्श को संभाला जाना है या अग्रेषित किया जाना है, UIScrollView एक टाइमर शुरू करता है जब आप इसे पहली बार स्पर्श करते हैं:

  • यदि आपने अपनी अंगुली को 150ms के भीतर महत्वपूर्ण रूप से स्थानांतरित नहीं किया है, तो यह घटना को आंतरिक दृश्य में पास करता है।

  • यदि आपने अपनी अंगुली को 150ms के भीतर महत्वपूर्ण रूप से स्थानांतरित कर दिया है, तो यह स्क्रॉलिंग शुरू करता है (और कभी भी ईवेंट को आंतरिक दृश्य में नहीं भेजता)।

    ध्यान दें कि जब आप किसी तालिका को स्पर्श करते हैं (जो स्क्रॉल व्यू का उप-वर्ग है) और तुरंत स्क्रॉल करना प्रारंभ करें, तो जिस पंक्ति को आपने स्पर्श किया है उसे कभी भी हाइलाइट नहीं किया जाता है।

  • यदि आपके पास है नहीं 150 मिलीमीटर के भीतर अपनी अंगुली को काफी हद तक ले जाया गया और UIScrollView ने ईवेंट को आंतरिक दृश्य में पास करना शुरू कर दिया, लेकिन फिर स्क्रॉलिंग शुरू करने के लिए आपने उंगली को काफी दूर ले जाया है, UIScrollView कॉल करता है touchesCancelled आंतरिक दृश्य पर और स्क्रॉलिंग शुरू होता है।

    ध्यान दें कि जब आप किसी तालिका को स्पर्श करते हैं, तो अपनी उंगली को थोड़ा सा रखें और फिर स्क्रॉल करना प्रारंभ करें, जिस पंक्ति को आपने स्पर्श किया है उसे पहले हाइलाइट किया गया है, लेकिन बाद में इसे हाइलाइट किया गया है।

घटनाओं के इन अनुक्रमों को UIScrollView की कॉन्फ़िगरेशन द्वारा बदला जा सकता है:

  • अगर delaysContentTouches नहीं है, तो कोई टाइमर उपयोग नहीं किया जाता है - घटनाएं तुरंत आंतरिक नियंत्रण में जाती हैं (लेकिन यदि आप अपनी अंगुली को काफी दूर ले जाते हैं तो रद्द कर दिया जाता है)
  • अगर cancelsTouches नहीं, फिर एक बार घटनाओं को नियंत्रण में भेजा जाता है, स्क्रॉलिंग कभी नहीं होगी।

ध्यान दें कि यह UIScrollView है जो प्राप्त करता है सब  touchesBegin, touchesMoved, touchesEnded तथा touchesCanceled CocoaTouch से घटनाओं (क्योंकि इसकी hitTestऐसा करने के लिए कहता है)। यह तब तक उन्हें आंतरिक दृश्य में आगे बढ़ाता है, जब तक वह चाहें, जब तक वह चाहें।

अब जब आप UIScrollView के बारे में सब कुछ जानते हैं, तो आप इसके व्यवहार को बदल सकते हैं। मैं शर्त लगा सकता हूं कि आप ऊर्ध्वाधर स्क्रॉलिंग को प्राथमिकता देना चाहते हैं, ताकि उपयोगकर्ता एक बार दृश्य को छू ले और अपनी उंगली (यहां तक ​​कि थोड़ा) चलाना शुरू कर दे, तो दृश्य लंबवत दिशा में स्क्रॉल करना शुरू कर देता है; लेकिन जब उपयोगकर्ता क्षैतिज दिशा में अपनी अंगुली को काफी दूर ले जाता है, तो आप लंबवत स्क्रॉलिंग को रद्द करना और क्षैतिज स्क्रॉलिंग शुरू करना चाहते हैं।

आप अपने बाहरी UIScrollView को उपclass करना चाहते हैं (कहें, आप अपनी कक्षा RemorsefulScrollView का नाम दें), ताकि डिफ़ॉल्ट व्यवहार के बजाय यह तुरंत सभी घटनाओं को आंतरिक दृश्य में आगे बढ़ाए, और केवल तभी जब महत्वपूर्ण क्षैतिज आंदोलन का पता चला हो, तो यह स्क्रॉल हो जाता है।

RemorsefulScrollView कैसे करें इस तरह व्यवहार करते हैं?

  • ऐसा लगता है कि वर्टिकल स्क्रॉलिंग और सेटिंग को अक्षम करना delaysContentTouches किसी को काम करने के लिए नेस्टेड UIScrollViews बनाना चाहिए। दुर्भाग्य से, यह नहीं करता है; UIScrollView तेज गति (जिसे अक्षम नहीं किया जा सकता है) के लिए कुछ अतिरिक्त फ़िल्टरिंग प्रतीत होता है, ताकि यदि UIScrollView को केवल क्षैतिज स्क्रॉल किया जा सके, तो यह हमेशा पर्याप्त ऊर्ध्वाधर गति को खाएगा (और अनदेखा करेगा)।

    प्रभाव इतनी गंभीर है कि नेस्टेड स्क्रॉल व्यू के अंदर लंबवत स्क्रॉलिंग अनुपयोगी है। (ऐसा प्रतीत होता है कि आपको बिल्कुल यह सेटअप मिला है, इसलिए इसे आज़माएं: 150ms के लिए एक उंगली पकड़ें, और उसके बाद इसे लंबवत दिशा में ले जाएं - नेस्टेड UIScrollView तब अपेक्षित काम करता है!)

  • इसका मतलब है कि आप इवेंट हैंडलिंग के लिए UIScrollView के कोड का उपयोग नहीं कर सकते हैं; आपको RemorsefulScrollView में सभी चार स्पर्श हैंडलिंग विधियों को ओवरराइड करना होगा और पहले अपनी प्रसंस्करण करना होगा, केवल ईवेंट को अग्रेषित करना होगा super (UIScrollView) यदि आपने क्षैतिज स्क्रॉलिंग के साथ जाने का निर्णय लिया है।

  • हालांकि आपको पास करना होगा touchesBegan UIScrollView को, क्योंकि आप भविष्य में क्षैतिज स्क्रॉलिंग के लिए आधार समन्वय को याद रखना चाहते हैं (यदि आप बाद में इसे तय करते हैं है एक क्षैतिज स्क्रॉलिंग)। आप भेजने में सक्षम नहीं होंगे touchesBegan बाद में UIScrollView पर, क्योंकि आप स्टोर नहीं कर सकते हैं touches तर्क: इसमें ऑब्जेक्ट्स हैं जो अगले से पहले उत्परिवर्तित हो जाएंगी touchesMoved घटना, और आप पुराने राज्य को पुन: पेश नहीं कर सकते हैं।

    तो आपको पास करना होगा touchesBegan UIScrollView को तुरंत देखें, लेकिन आप आगे छुपाएंगे touchesMoved जब तक आप क्षैतिज स्क्रॉल करने का निर्णय नहीं लेते तब तक इसकी घटनाएं। नहीं touchesMoved मतलब कोई स्क्रॉलिंग नहीं है, तो यह प्रारंभिक touchesBegan कोई नुकसान नहीं होगा। लेकिन सेट करो delaysContentTouches नहीं, ताकि कोई अतिरिक्त आश्चर्य टाइमर हस्तक्षेप न करें।

    (ऑफटॉपिक - आपके विपरीत, UIScrollView कर सकते हैं स्टोर ठीक से छूता है और मूल को पुन: उत्पन्न और अग्रेषित कर सकता है touchesBegan बाद में घटना अप्रकाशित एपीआई का उपयोग करने का इसका अनुचित लाभ है, इसलिए वे म्यूट किए जाने से पहले टच ऑब्जेक्ट्स क्लोन कर सकते हैं।)

  • यह देखते हुए कि आप हमेशा आगे बढ़ते हैं touchesBegan, आपको भी आगे बढ़ना होगा touchesCancelled तथा touchesEnded। आपको बारी करना है touchesEnded में touchesCancelledहालांकि, क्योंकि UIScrollView व्याख्या करेगा touchesBegan, touchesEnded अनुक्रम एक स्पर्श-क्लिक के रूप में, और इसे आंतरिक दृश्य में अग्रेषित करेगा। आप पहले से ही उचित घटनाओं को अग्रेषित कर रहे हैं, इसलिए आप कभी भी यूआईएसक्रॉल व्यू को कुछ भी अग्रेषित नहीं करना चाहते हैं।

मूल रूप से यहां आपको छद्म कोड है जो आपको करने की ज़रूरत है। सादगी के लिए, मैं मल्टीटाउच घटना के बाद क्षैतिज स्क्रॉलिंग की अनुमति नहीं देता।

// RemorsefulScrollView.h

@interface RemorsefulScrollView : UIScrollView {
  CGPoint _originalPoint;
  BOOL _isHorizontalScroll, _isMultitouch;
  UIView *_currentChild;
}
@end

// RemorsefulScrollView.m

// the numbers from an example in Apple docs, may need to tune them
#define kThresholdX 12.0f
#define kThresholdY 4.0f

@implementation RemorsefulScrollView

- (id)initWithFrame:(CGRect)frame {
  if (self = [super initWithFrame:frame]) {
    self.delaysContentTouches = NO;
  }
  return self;
}

- (id)initWithCoder:(NSCoder *)coder {
  if (self = [super initWithCoder:coder]) {
    self.delaysContentTouches = NO;
  }
  return self;
}

- (UIView *)honestHitTest:(CGPoint)point withEvent:(UIEvent *)event {
  UIView *result = nil;
  for (UIView *child in self.subviews)
    if ([child pointInside:point withEvent:event])
      if ((result = [child hitTest:point withEvent:event]) != nil)
        break;
  return result;
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesBegan:touches withEvent:event]; // always forward touchesBegan -- there's no way to forward it later
    if (_isHorizontalScroll)
      return; // UIScrollView is in charge now
    if ([touches count] == [[event touchesForView:self] count]) { // initial touch
      _originalPoint = [[touches anyObject] locationInView:self];
    _currentChild = [self honestHitTest:_originalPoint withEvent:event];
    _isMultitouch = NO;
    }
  _isMultitouch |= ([[event touchesForView:self] count] > 1);
  [_currentChild touchesBegan:touches withEvent:event];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
  if (!_isHorizontalScroll && !_isMultitouch) {
    CGPoint point = [[touches anyObject] locationInView:self];
    if (fabsf(_originalPoint.x - point.x) > kThresholdX && fabsf(_originalPoint.y - point.y) < kThresholdY) {
      _isHorizontalScroll = YES;
      [_currentChild touchesCancelled:[event touchesForView:self] withEvent:event]
    }
  }
  if (_isHorizontalScroll)
    [super touchesMoved:touches withEvent:event]; // UIScrollView only kicks in on horizontal scroll
  else
    [_currentChild touchesMoved:touches withEvent:event];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
  if (_isHorizontalScroll)
    [super touchesEnded:touches withEvent:event];
    else {
    [super touchesCancelled:touches withEvent:event];
    [_currentChild touchesEnded:touches withEvent:event];
    }
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
  [super touchesCancelled:touches withEvent:event];
  if (!_isHorizontalScroll)
    [_currentChild touchesCancelled:touches withEvent:event];
}

@end

मैंने इसे चलाने या यहां तक ​​कि संकलित करने की कोशिश नहीं की है (और पूरे वर्ग को एक सादे पाठ संपादक में टाइप किया है), लेकिन आप उपर्युक्त से शुरू कर सकते हैं और उम्मीद है कि यह काम कर रहा है।

एकमात्र छिपी हुई पकड़ मैं देखता हूं कि यदि आप RemorsefulScrollView पर किसी भी गैर-यूआईएसक्रॉल व्यू बच्चे के विचार जोड़ते हैं, तो आप बच्चे को अग्रेषित स्पर्श ईवेंट प्रतिक्रियाकर्ता श्रृंखला के माध्यम से वापस आ सकते हैं, अगर बच्चा हमेशा UIScrollView करता है जैसे स्पर्श को संभाल नहीं करता है। एक बुलेट प्रूफ RemorsefulScrollView कार्यान्वयन के खिलाफ सुरक्षा होगी touchesXxx पुनः प्रवेश।

दूसरी रणनीति: अगर किसी कारण से नेस्टेड UIScrollViews काम नहीं करते हैं या सही होने के लिए बहुत मेहनत नहीं करते हैं, तो आप इसे केवल एक UIScrollView के साथ प्राप्त करने का प्रयास कर सकते हैं, इसे स्विच कर सकते हैं pagingEnabled आप से फ्लाई पर संपत्ति scrollViewDidScroll प्रतिनिधि विधि।

विकर्ण स्क्रॉलिंग को रोकने के लिए, आपको पहले सामग्री को याद रखने की कोशिश करनी चाहिए scrollViewWillBeginDragging, और अंदर सामग्री ऑफसेट की जांच और रीसेट कर रहा है scrollViewDidScroll यदि आप एक विकर्ण आंदोलन का पता लगाते हैं। कोशिश करने की एक और रणनीति है सामग्री को रीसेट करना आकार केवल एक दिशा में स्क्रॉलिंग को सक्षम करने के लिए, एक बार जब आप तय करते हैं कि उपयोगकर्ता की उंगली किस दिशा में जा रही है। (UIScrollView सामग्री के साथ झुकाव के बारे में बहुत क्षमा कर रहा है आकार और सामग्री अपने प्रतिनिधि तरीकों से ऑफसेट करें।)

यदि वह या तो काम नहीं करता है या नाराज दृश्यों में परिणाम देता है, तो आपको ओवरराइड करना होगा touchesBegan, touchesMoved इत्यादि और UIScrollView को विकर्ण आंदोलन घटनाओं को आगे नहीं बढ़ाएं। (हालांकि उपयोगकर्ता अनुभव इस मामले में उप-शीर्ष होगा, क्योंकि आपको उन्हें एक दिशा में मजबूर करने के बजाय विकर्ण आंदोलनों को अनदेखा करना होगा। यदि आप वास्तव में साहसी महसूस कर रहे हैं, तो आप अपना खुद का यूआईटीच लुकलाइक लिख सकते हैं, जैसे कि रीवेन टच। उद्देश्य -सी सादा पुराना सी है, और सी की तुलना में दुनिया में और अधिक डकटाइप नहीं है; जब तक कोई भी वस्तु के वास्तविक वर्ग की जांच नहीं करता है, जिसे मैं मानता हूं कि कोई भी नहीं करता है, तो आप किसी भी वर्ग को किसी अन्य वर्ग की तरह दिख सकते हैं। यह खुलता है आप चाहते हैं कि किसी भी समन्वय के साथ, आप चाहते हैं कि किसी भी स्पर्श को संश्लेषित करने की संभावना है।)

बैकअप रणनीति: UTScrollView में एक Sane पुनर्मूल्यांकन TTScrollView है तीन20 पुस्तकालय। दुर्भाग्य से यह उपयोगकर्ता को बहुत ही अप्राकृतिक और गैर-iphonish लगता है। लेकिन यदि UIScrollView का उपयोग करने का हर प्रयास विफल रहता है, तो आप एक कस्टम-कोडित स्क्रॉल व्यू पर वापस आ सकते हैं। यदि संभव हो तो मैं इसके खिलाफ अनुशंसा करता हूं; UIScrollView का उपयोग करके सुनिश्चित करता है कि आप देशी दिखने और महसूस कर रहे हैं, इससे कोई फर्क नहीं पड़ता कि यह भविष्य में आईफोन ओएस संस्करणों में कैसे विकसित होता है।

ठीक है, इस छोटे निबंध थोड़ा सा लंबा हो गया। कई दिनों पहले स्क्रॉलिंग मैडनेस पर काम के बाद मैं अभी भी यूआईएसक्रॉल व्यू गेम में हूं।

अनुलेख यदि आपको इनमें से कोई भी काम मिल रहा है और साझा करना पसंद है, तो कृपया मुझे andreyvit@gmail.com पर प्रासंगिक कोड ई-मेल करें, मैं खुशी से इसे अपने ट्रिक्स की स्क्रॉलिंग मैडनेस बैग

P.P.S. स्क्रॉलिंग मैडनेस रीडमे में इस छोटे निबंध को जोड़ना।


113
2018-05-10 03:28



ध्यान दें कि यह नेस्टेड स्क्रॉलव्यू व्यवहार अब एसडीके में बॉक्स से बाहर काम करता है, कोई मजाकिया व्यवसाय की आवश्यकता नहीं है - andygeers
एंडीजर्स टिप्पणी को +1 किया, फिर एहसास हुआ कि यह सटीक नहीं है; आप अभी भी शुरुआती बिंदु से तिरछे खींचकर नियमित UIScrollView को "तोड़ सकते हैं" और फिर आपने "स्क्रोलर खो दिया" खींचा है और यह तब तक दिशात्मक लॉक को अनदेखा कर देगा जब तक कि आप रिलीज नहीं करते और भगवान को समाप्त नहीं करते हैं। - Kalle
महान पीछे के दृश्यों के स्पष्टीकरण के लिए धन्यवाद! मैं नीचे मैटियास वाडमैन के समाधान के साथ गया जो थोड़ा कम आक्रामक आईएमओ दिखता है। - Ortwin Gentz
यह उत्तर अब यह अपडेट करना बहुत अच्छा होगा कि UIScrollView ने अपने पैन इशारा पहचानकर्ता को उजागर किया है। (लेकिन शायद वह मूल दायरे से बाहर है।) - jtbandes
क्या इस पोस्ट को अपडेट करने की संभावना है? ग्रेट पोस्ट और आपके इनपुट के लिए धन्यवाद। - Pavan


यह हर बार मेरे लिए काम करता है ...

scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * NumberOfPages, 1);

51
2017-07-07 18:51



किसी और के लिए इस सवाल पर ठोकर खा रहा है: मुझे लगता है कि यह जवाब उस संपादन से पहले पोस्ट किया गया था जिसने प्रश्न स्पष्ट किया था। यह आपको अनुमति देगा केवल क्षैतिज स्क्रॉल करें, यह लंबवत या क्षैतिज स्क्रॉल करने में सक्षम होने के मुद्दे को संबोधित नहीं करता है बल्कि विकर्ण रूप से। - andygeers
मेरे लिए एक आकर्षण की तरह काम करता है। मेरे पास पेजिंग के साथ एक बहुत लंबा क्षैतिज स्क्रॉल व्यू है, और प्रत्येक पृष्ठ पर एक UIWebView है, जो मुझे आवश्यक लंबवत स्क्रॉलिंग को संभालता है। - Tom Redman
अति उत्कृष्ट! लेकिन क्या कोई यह समझा सकता है कि यह कैसे काम करता है (सामग्री सेट करना ऊंचाई 1 तक)! - Praveen
यह वास्तव में काम करता है, लेकिन यह क्यों और कैसे काम करता है? क्या कोई इससे कुछ समझ सकता है? - Marko Francekovic


मेरे जैसे आलसी लोगों के लिए:

सेट scrollview.directionalLockEnabled सेवा मेरे YES

- (void) scrollViewWillBeginDragging: (UIScrollView *) scrollView
{
    self.oldContentOffset = scrollView.contentOffset;
}

- (void) scrollViewDidScroll: (UIScrollView *) scrollView
{
    if (scrollView.contentOffset.x != self.oldContentOffset.x)
    {
        scrollView.pagingEnabled = YES;
        scrollView.contentOffset = CGPointMake(scrollView.contentOffset.x,
                                               self.oldContentOffset.y);
    }
    else
    {
        scrollView.pagingEnabled = NO;
    }
}

- (void) scrollViewDidEndDecelerating: (UIScrollView *) scrollView
{
    self.oldContentOffset = scrollView.contentOffset;
}

23
2017-11-12 12:17



इच्छा है कि मैं इसे स्वीकार्य उत्तर दे सकता हूं। - maksa


मैंने इस समस्या को हल करने के लिए निम्न विधि का उपयोग किया, उम्मीद है कि यह आपकी मदद करेगी।

सबसे पहले अपने नियंत्रक शीर्षलेख फ़ाइल में निम्न चर परिभाषित करें।

CGPoint startPos;
int     scrollDirection;

startPos रखेंगे contentOffset मूल्य जब आपके प्रतिनिधि को प्राप्त होता है scrollViewWillBeginDragging संदेश। तो इस विधि में हम यह करते हैं;

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
    startPos = scrollView.contentOffset;
    scrollDirection=0;
}

तो हम इन मानों का उपयोग उपयोगकर्ताओं को स्क्रॉल दिशा में निर्धारित करने के लिए करते हैं scrollViewDidScroll संदेश।

- (void)scrollViewDidScroll:(UIScrollView *)scrollView{

   if (scrollDirection==0){//we need to determine direction
       //use the difference between positions to determine the direction.
       if (abs(startPos.x-scrollView.contentOffset.x)<abs(startPos.y-scrollView.contentOffset.y)){          
          NSLog(@"Vertical Scrolling");
          scrollDirection=1;
       } else {
          NSLog(@"Horitonzal Scrolling");
          scrollDirection=2;
       }
    }
//Update scroll position of the scrollview according to detected direction.     
    if (scrollDirection==1) {
       [scrollView setContentOffset:CGPointMake(startPos.x,scrollView.contentOffset.y) animated:NO];
    } else if (scrollDirection==2){
       [scrollView setContentOffset:CGPointMake(scrollView.contentOffset.x,startPos.y) animated:NO];
    }
 }

आखिर में जब उपयोगकर्ता खींचते हैं तो हमें सभी अपडेट ऑपरेशंस को रोकना होगा;

 - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
    if (decelerate) {
       scrollDirection=3;
    }
 }

16
2017-11-09 15:41



हम्म ... असल में, अधिक जांच के बाद - यह काम करता है सुंदर ठीक है, लेकिन मुसीबत यह है कि यह मंदी के चरण के दौरान दिशा का नियंत्रण खो देता है - इसलिए यदि आप अपनी अंगुली को तिरछे ढंग से आगे बढ़ना शुरू करते हैं तो यह केवल क्षैतिज या लंबवत स्थानांतरित हो जाएगा जब तक आप जाने नहीं देते जिस बिंदु पर यह थोड़ी देर के लिए एक विकर्ण दिशा में कम हो जाएगा - andygeers
@andygeers, अगर यह बेहतर काम कर सकता है - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{ if (decelerate) { scrollDirection=3; } } बदल दिया गया था - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{ if (!decelerate) { scrollDirection=0; } } तथा - (void)scrollViewDidEndDecelerating{ scrollDirection=0; } - cduck
मेरे लिए काम नहीं किया सामग्री को सेट करना उड़ान में ऑफसेट पेजिंग व्यवहार को नष्ट करना प्रतीत होता है। मैं मैटियास वाडमैन के समाधान के साथ गया। - Ortwin Gentz


मैं यहां कब्र हो सकता हूं, लेकिन आज मैं इस पोस्ट पर ठोकर खाई क्योंकि मैं एक ही समस्या को हल करने की कोशिश कर रहा था। मेरा समाधान यहाँ है, ऐसा लगता है कि बहुत अच्छा काम कर रहा है।

मैं सामग्री की एक स्क्रीनफुल प्रदर्शित करना चाहता हूं, लेकिन उपयोगकर्ता को 4 अन्य स्क्रीनफुलों में से एक को बाएं और दाएं नीचे स्क्रॉल करने की अनुमति देता हूं। मेरे पास 320x480 आकार और 960x1440 की सामग्री आकार के साथ एक एकल UIScrollView है। सामग्री ऑफ़सेट 320,480 पर शुरू होता है। ScrollViewDidEndDecelerating में :, मैंने 5 विचारों (केंद्र दृश्य और इसके चारों ओर 4) को दोबारा खींचा है, और सामग्री ऑफसेट को 320,480 पर रीसेट कर दिया है।

मेरे समाधान का मांस यहां है, scrollViewDidScroll: विधि।

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{   
    if (!scrollingVertically && ! scrollingHorizontally)
    {
        int xDiff = abs(scrollView.contentOffset.x - 320);
        int yDiff = abs(scrollView.contentOffset.y - 480);

        if (xDiff > yDiff)
        {
            scrollingHorizontally = YES;
        }
        else if (xDiff < yDiff)
        {
            scrollingVertically = YES;
        }
    }

    if (scrollingHorizontally)
    {
        scrollView.contentOffset = CGPointMake(scrollView.contentOffset.x, 480);
    }
    else if (scrollingVertically)
    {
        scrollView.contentOffset = CGPointMake(320, scrollView.contentOffset.y);
    }
}

13
2018-03-04 01:04



आपको शायद यह पता चलेगा कि जब उपयोगकर्ता स्क्रॉल व्यू पर जाने देता है तो यह कोड अच्छी तरह से "कम हो जाता है" - यह मृत बंद हो जाएगा। यदि आप मंदी नहीं चाहते हैं तो यह आपके लिए अच्छा हो सकता है। - andygeers


दोस्तों को सबव्यू ऊंचाई को स्क्रॉल व्यू ऊंचाई और सामग्री आकार की ऊंचाई के समान बनाने के समान सरल है। फिर लंबवत स्क्रॉलिंग अक्षम है।


4
2018-06-05 19:26



किसी और के लिए इस सवाल पर ठोकर खा रहा है: मुझे लगता है कि यह जवाब उस संपादन से पहले पोस्ट किया गया था जिसने प्रश्न स्पष्ट किया था। यह आपको केवल क्षैतिज स्क्रॉल करने की अनुमति देगा, यह लंबवत या क्षैतिज स्क्रॉल करने में सक्षम होने के मुद्दे को संबोधित नहीं करता है बल्कि विकर्ण रूप से नहीं। - andygeers


यहां एक पेजेड का मेरा कार्यान्वयन है UIScrollView जो केवल ऑर्थोगोनल स्क्रॉल की अनुमति देता है। सेट करना सुनिश्चित करें pagingEnabled सेवा मेरे YES

PagedOrthoScrollView.h

@interface PagedOrthoScrollView : UIScrollView
@end

PagedOrthoScrollView.m

#import "PagedOrthoScrollView.h"

typedef enum {
  PagedOrthoScrollViewLockDirectionNone,
  PagedOrthoScrollViewLockDirectionVertical,
  PagedOrthoScrollViewLockDirectionHorizontal
} PagedOrthoScrollViewLockDirection; 

@interface PagedOrthoScrollView ()
@property(nonatomic, assign) PagedOrthoScrollViewLockDirection dirLock;
@property(nonatomic, assign) CGFloat valueLock;
@end

@implementation PagedOrthoScrollView
@synthesize dirLock;
@synthesize valueLock;

- (id)initWithFrame:(CGRect)frame {
  self = [super initWithFrame:frame];
  if (self == nil) {
    return self;
  }

  self.dirLock = PagedOrthoScrollViewLockDirectionNone;
  self.valueLock = 0;

  return self;
}

- (void)setBounds:(CGRect)bounds {
  int mx, my;

  if (self.dirLock == PagedOrthoScrollViewLockDirectionNone) {
    // is on even page coordinates, set dir lock and lock value to closest page 
    mx = abs((int)CGRectGetMinX(bounds) % (int)CGRectGetWidth(self.bounds));
    if (mx != 0) {
      self.dirLock = PagedOrthoScrollViewLockDirectionHorizontal;
      self.valueLock = (round(CGRectGetMinY(bounds) / CGRectGetHeight(self.bounds)) *
                        CGRectGetHeight(self.bounds));
    } else {
      self.dirLock = PagedOrthoScrollViewLockDirectionVertical;
      self.valueLock = (round(CGRectGetMinX(bounds) / CGRectGetWidth(self.bounds)) *
                        CGRectGetWidth(self.bounds));
    }

    // show only possible scroll indicator
    self.showsVerticalScrollIndicator = dirLock == PagedOrthoScrollViewLockDirectionVertical;
    self.showsHorizontalScrollIndicator = dirLock == PagedOrthoScrollViewLockDirectionHorizontal;
  }

  if (self.dirLock == PagedOrthoScrollViewLockDirectionHorizontal) {
    bounds.origin.y = self.valueLock;
  } else {
    bounds.origin.x = self.valueLock;
  }

  mx = abs((int)CGRectGetMinX(bounds) % (int)CGRectGetWidth(self.bounds));
  my = abs((int)CGRectGetMinY(bounds) % (int)CGRectGetHeight(self.bounds));

  if (mx == 0 && my == 0) {
    // is on even page coordinates, reset lock
    self.dirLock = PagedOrthoScrollViewLockDirectionNone;
  }

  [super setBounds:bounds];
}

@end

3
2017-08-28 13:59



आईओएस 7 पर भी अच्छा काम करता है। धन्यवाद! - Ortwin Gentz


मुझे भी इस समस्या को हल करना पड़ा है, और एंड्री Tarantsov के जवाब में निश्चित रूप से समझने के लिए बहुत उपयोगी जानकारी है UIScrollViews काम, मुझे लगता है कि समाधान थोड़ा अधिक जटिल है। मेरा समाधान, जिसमें कोई सबक्लासिंग या टच अग्रेषण शामिल नहीं है, निम्नानुसार है:

  1. प्रत्येक दिशा के लिए दो नेस्टेड स्क्रॉल दृश्य बनाएं।
  2. दो डमी बनाएं UIPanGestureRecognizers, प्रत्येक दिशा के लिए फिर से एक।
  3. के बीच विफलता निर्भरता बनाएँ UIScrollViews'PanGestureRecognizer गुण और डमी UIPanGestureRecognizer उपयोग करके अपने UIScrollView की वांछित स्क्रॉलिंग दिशा के लंबवत दिशा के अनुरूप UIGestureRecognizer's  -requireGestureRecognizerToFail: चयनकर्ता।
  4. में -gestureRecognizerShouldBegin: आपके डमी UIPanGestureRecognizers के लिए कॉलबैक, इशारा करते हुए पैन की प्रारंभिक दिशा की गणना करें- ट्रांसलेशन इनव्यू: चयनकर्ता (आपका UIPanGestureRecognizers जब तक आपके स्पर्श ने पैन के रूप में पंजीकरण करने के लिए पर्याप्त अनुवाद नहीं किया है तब तक इस प्रतिनिधि कॉलबैक को कॉल नहीं किया जाएगा)। गणना की गई दिशा के आधार पर शुरू करने के लिए अपने इशारा पहचानकर्ता को अनुमति दें या अस्वीकार करें, जो बदले में लंबवत UIScrollView पैन इशारा पहचानकर्ता को शुरू करने की अनुमति दी जानी चाहिए या नहीं।
  5. में -gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:, अपने डमी की अनुमति न दें UIPanGestureRecognizers स्क्रॉलिंग के साथ चलाने के लिए (जब तक कि आपके पास कुछ अतिरिक्त व्यवहार नहीं है जिसे आप जोड़ना चाहते हैं)।

3
2017-07-02 18:50





मैंने जो किया वह दृश्य स्क्रीन के आकार के फ्रेम के साथ एक पेजिंग UIScrollView बना रहा था और सामग्री की आकार को मेरी सभी सामग्री और 1 की ऊंचाई (धन्यवाद टोनटेल) की आवश्यकता के लिए सेट किया गया था। फिर मैंने प्रत्येक पृष्ठ पर सेट किए गए फ्रेम के साथ मेनू UIScrollView पेज बनाए, दृश्य स्क्रीन का आकार, और प्रत्येक की सामग्री आकार को स्क्रीन की चौड़ाई और प्रत्येक के लिए आवश्यक ऊंचाई सेट करें। तब मैंने बस मेनू मेनू में से प्रत्येक पेजिंग दृश्य में जोड़ा। सुनिश्चित करें कि पेजिंग स्क्रॉल दृश्य पर पेजिंग सक्षम है लेकिन मेनू दृश्यों पर अक्षम (डिफ़ॉल्ट रूप से अक्षम होना चाहिए) और आपको जाने के लिए अच्छा होना चाहिए।

पेजिंग स्क्रॉल दृश्य अब क्षैतिज स्क्रॉल करता है, लेकिन सामग्री की ऊंचाई के कारण लंबवत नहीं है। प्रत्येक पृष्ठ लंबवत रूप से स्क्रॉल करता है लेकिन इसकी सामग्री आकार की बाधाओं के कारण क्षैतिज रूप से नहीं।

यहां कोड है यदि उस स्पष्टीकरण ने कुछ वांछित होने के लिए छोड़ा:

UIScrollView *newPagingScrollView =  [[UIScrollView alloc] initWithFrame:self.view.bounds]; 
[newPagingScrollView setPagingEnabled:YES];
[newPagingScrollView setShowsVerticalScrollIndicator:NO];
[newPagingScrollView setShowsHorizontalScrollIndicator:NO];
[newPagingScrollView setDelegate:self];
[newPagingScrollView setContentSize:CGSizeMake(self.view.bounds.size.width * NumberOfDetailPages, 1)];
[self.view addSubview:newPagingScrollView];

float pageX = 0;

for (int i = 0; i < NumberOfDetailPages; i++)
{               
    CGRect pageFrame = (CGRect) 
    {
        .origin = CGPointMake(pageX, pagingScrollView.bounds.origin.y), 
        .size = pagingScrollView.bounds.size
    };
    UIScrollView *newPage = [self createNewPageFromIndex:i ToPageFrame:pageFrame]; // newPage.contentSize custom set in here        
    [pagingScrollView addSubview:newPage];

    pageX += pageFrame.size.width;  
}           

2
2017-09-12 18:08