SORU
7 NİSAN 2009, Salı


UİScrollView : disk belleği yatay, dikey kaydırma?

Nasıl hangi belleği ve kaydırma sadece dikey ya da sadece yatay olarak belirli bir anda taşımak için UIScrollView zorlayabilir miyim?

Benim anlayışıma göre directionalLockEnabled özelliği bunu başarmak gerektiğini, ancak bir çapraz tokatlamak hala tek bir eksen için hareket kısıtlanması yerine çapraz kaydırma görünümü neden olur.

Kullanıcı yatay kaydırma için izin istiyorum, daha net olmak YA da dikey olarak, ancak her ikisini de aynı anda. Edit:

CEVAP
10 Mayıs 2009, Pazar


Çok zor bir durumda olduğunu söylemeliyim.

pagingEnabled=YES ile bir UİScrollView sayfaları arasında geçiş yapmak için kullanmanız gerektiğini unutmayın, ama pagingEnabled=NO dikey olarak ilerleyin.

2 Olası stratejiler vardır. Uygulamak kolaydır / çalışmak, hem denemek olacak bilmiyorum.

İlk:iç içe UİScrollViews. Açıkçası, henüz bu iş için var olan bir kişi görmeye geldim. Ancak yeterince şahsen denemedim ve benim sıkı çalış yeter yaptığınızda, 43 ** gösteriyor.

Strateji dış kaydırma görünümü yalnızca yatay kaydırma ve iç sadece dikey kaydırma işlemek için kaydırma manzarası halledeyim. Bunu başarmak için, UİScrollView nasıl içten bilmeniz gerekir. Tüm dokunma olayları UİScrollView böyle bir o hitTest yöntem geçersiz kılar ve her zaman kendisi verir. Sonra içeri touchesBegan, touchesMoved vb eğer olay ilgilenen varsa kontrol eder, ya da iç bileşenleri için kolları geçer.

Eğer dokunmatik muamele olup olmadığını karar vermek ya da iletilmek üzere, UİScrollView ilk dokunduğumda bir zamanlayıcı başlar

  • Eğer parmağınızı dokunmamışsın bile 150ms, içinde önemli ölçüde iç görünüm için olay geçer.

  • 150ms, kaydırma başlar (ve hiç iç görünüm için olay geçer) önemli ölçüde içinde parmağını taşınmış.

    Not nasıl bir tablo kaydırma görünümü bir alt sınıfı olan) dokunma ve hemen kaydırma başladığında, asla vurgulanan sana dokunan bir satır.

  • Eğer varsadeğil150ms ve UİScrollView önemli ölçüde içinde parmağını taşındı iç görünüm, ama . olaylar geçirmeden başladı ^em>sonraparmak kaydırma başlamak için yeterince uzağa taşınmış, UİScrollView iç görünüm touchesCancelled aramalar ve kaymaya başlar.

    Tablo dokunun, parmağınızı biraz basılı tutun ve kaydırma başlatın, sana dokunan ilk satır vurgulanır, ancak de vurgulanan sonrasında nasıl not.

Olayların bu sıra UİScrollView yapılandırma tarafından değiştirilebilir:

  • Eğer delaysContentTouches HAYIR, hayır zamanlayıcı kullanılır olayları derhal iç denetim (ama eğer parmağınızı yeterince hareket edersen iptal edilir)
  • Eğer cancelsTouches ise, o zaman olayları kontrol etmek için gönderilen bir kez, kaydırma asla olmayacak.

Aldığı UİScrollView olduğunu unutmayıntümtouchesBegin, touchesMoved, touchesEnded touchesCanceled CocoaTouch olayları hitTest bunu yapmak için söyler çünkü). O zaman gönderirse, o istediği sürece isterse iç görünüm için onları.

UİScrollView hakkında her şeyi biliyoruz, onun davranışını değiştirebilir. Ben bahis size tercih için dikey kaydırma, böylece bir kez kullanıcı dokunur görünüm ve başlar hareketli parmak (hatta biraz), görünümünü başlatır kaydırma dikey yönde; ama ne zaman kullanıcı hareket parmağını yatay yönde yeterince uzağa, ister iptal dikey kaydırma ve yatay kaydırma başlatın.

İstediğiniz alt dış UİScrollView (ki, senin adın sınıf RemorsefulScrollView), böylece yerine varsayılan davranışı hemen ileten tüm olaylar için iç görünüm, ve sadece zaman önemli yatay hareketi tespit kaydırır.

Nasıl yapmak RemorsefulScrollView bu şekilde davranır?

  • Dikey kaydırma devre dışı bırakmak ve YOK etmek delaysContentTouches ayarı iç içe UİScrollViews çalışma yapmak gerekir gibi görünüyor. Ne yazık ki, değildir; UİScrollView görünür yapmak için bazı ek filtreleme için hızlı hareketleri (cannot be disabled), böylece bile UİScrollView sadece kaydırılan yatay olarak, daima ye (Yoksay) yeterince hızlı dikey hareketleri.

    Etkisi kaydırma iç içe geçmiş bir görünüm içinde dikey kaydırma kullanılamaz, böylece önemli. (Tam olarak bu kurulum var gibi görünüyor, bunu deneyin: 150ms ve sonra da düşey doğrultuda iç içe UİScrollView daha sonra beklendiği gibi çalışır! bir parmak tutun)

  • Bu demektir kullanamazsınız UİScrollView kodu için olay işleme; geçersiz kılmak için dört dokunma işleme yöntemleri RemorsefulScrollView ve kendi işleme ilk olarak, yalnızca yönlendirme olayı super (UİScrollView) eğer karar için yatay kaydırma.

  • Ancak, gelecek için yatay kaydırma koordinat (daha sonra karar verirseniz . bir baz hatırlamak istiyorum çünkü touchesBegan UİScrollView geçmeli, ^em>bir yatay kaydırma). Sen mümkün olmayacaktır gönder touchesBegan UİScrollView daha sonra, çünkü açamıyor deposu touches bağımsız değişken: içerdiği nesneler olacak mutasyona uğramış önceki sonraki touchesMoved olay ve yeniden eski Devlet.

    touchesBegan hemen UİScrollView geçmek zorunda, ama yatay kaydırma için karar verene kadar, ondan touchesMoved başka olayları gizlemek. touchesMoved kaydırma anlamına gelir Hayır, bu ilk touchesBegan kimse zarar vermez. Ama ek bir sürpriz zamanlayıcılar engel YOK delaysContentTouches ayarlayın.

    (Offtopic — senin aksine, UİScrollViewolabilirdokunur düzgün mağaza ve ilet touchesBegan orijinal olay daha sonra yeniden olabilir. Yayınlanmamış API kullanarak haksız bir avantaja sahiptir, bu yüzden mutasyona önce dokunmatik nesneleri klon olabilir.)

  • Her zaman ileri touchesBegan, sen de ileriye doğru 29 ** göz önüne alınırsa, ve touchesEnded. Teslim etmen gerek touchesEnded touchesCancelled, ancak, çünkü UİScrollView ki yorumlar touchesBegan, touchesEnded dizisi gibi, dokunma tıklayın ve dört gözle iç görünüm. Zaten doğru olayları kendini yönlendirme, asla UİScrollView ileri bir şey istiyorum.

Temelde işte yapmanız gerekenler için yalancı. Basitlik için, ben hiç çoklu dokunma olay ortaya çıktıktan sonra yatay kaydırma sağlar.

// 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

Hatta bu derleme çalıştırmak için (ve bir düz metin düzenleyicisinde bütün sınıf yazılmış) denemedim ama yukarıdaki ile başlar ve inşallah çalışmaya başlayabilirsiniz.

Tek gizli yakalamak görüyorum ki eğer eklediğiniz olmayan UİScrollView çocuk görüşlere RemorsefulScrollView, dokunma olayları iletmek için bir çocuktan geri gelmesi için) yanıtlayıcı zinciri, eğer çocuk değil her zaman ele dokunur gibi UİScrollView. -Kurşun geçirmez RemorsefulScrollView bir uygulama touchesXxx giriş karşı korurdu.

İkinci strateji:Eğer nedeniyle nedense iç içe UİScrollViews çalışmıyor veya kanıtlamak çok zor değil, onlara iyi davranın ile sadece bir UİScrollView, anahtarlama pagingEnabled özellik fly scrollViewDidScroll temsilci yöntemi.

Çapraz kaydırma önlemek için, ilk eğer diyagonal bir hareket tespit ederseniz scrollViewWillBeginDragging contentOffset hatırlayarak ve contentOffset scrollViewDidScroll iç kontrol sıfırlamayı denemelisin. Denemek için başka bir strateji contentSize sadece kullanıcının parmağı olan karar bir kez bir yönde kaydırma etkinleştirmek için sıfırlamak için. (UİScrollView contentSize ve temsilci kendi yöntemleri contentOffset göreceği konusunda oldukça bağışlayıcı görünüyor.)

Eğer bu kadar baştan savma görseller ya da sonuçları çalışmazsa, touchesBegan, touchesMoved ileri vb çapraz hareket olayları UİScrollView için geçersiz kılmak gerekir. (Kullanıcı deneyimi çapraz hareketleri görmezden tek bir yöne doğru onları zorlamak yerine, çünkü bu durumda ancak altında olacak. Eğer gerçekten maceracı hissediyorsanız, kendi UİTouch sana çok benzeyen yazabilirsiniz, bir şey RevengeTouch gibi. Objective-C düz eski C ve yapacak başka bir şey yok ducktypeful dünya daha C; sürece kimse çekler gerçek sınıf nesneleri, sanırım kimse yok, sen-ebilmek yapmak herhangi bir sınıf gibi başka bir sınıf. Bu herhangi istediğiniz koordinatları ile istediğiniz herhangi dokunur sentezlemek için bir olasılık açılır.)

Yedekleme stratejisi:TTScrollView, Three20 library UİScrollView aklı başında bir reimplementation var. Ne yazık ki çok doğal değil ve olmayan iphonish kullanıcı için. Ama eğer UİScrollView kullanarak her girişim başarısız olursa, özel kodlu bir kaydırma görüntülemek için geri düşebilir. Eğer buna karşı Olası öneririm; UİScrollView kullanarak görünümünü, geleceği iPhone OS sürümleri geliştikçe olursa olsun yerli almanızı sağlar.

Tamam, bu biraz deneme biraz fazla uzamıştı. Sadece ScrollingMadness çalışmaları birkaç gün önce sonra UİScrollView oyunları hala benim.

Bu çalışma herhangi olsun ve lütfen paylaşım gibi hissediyorum P. S. e-posta ilgili kodu bana andreyvit@gmail.com mutlu benim içine dahil ederim ScrollingMadness bag of tricks.

P. P. S. bu küçük deneme README ScrollingMadness Ekleme.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Darren Kitchen

    Darren Kitch

    3 EKİM 2011
  • Jejoab

    Jejoab

    4 NİSAN 2008
  • The Fashion Sight

    The Fashion

    22 AĞUSTOS 2011