2013-08-30 22 views
5

SUPER EDYCJA:Płynne przewijanie z ponad 500 obrazami

W porządku, po kilku różnych zmianach mam jaśniejsze pytanie. Zasadniczo zmagam się z używaniem NSCache. Mam widok kolekcji, jak widać poniżej i chcę być w stanie zminimalizować opóźnienie przewijania z obrazami, które robię w większości przypadków. Trudną częścią jest przejście na pełnowymiarowy obraz. Jest w innym widoku i chciałbym przejść do pełnowymiarowego zdjęcia, podobnie jak Apple do aplikacji ze zdjęciami.

Wygląda na to, że Apple buforuje obrazy i uzyskuje do nich dostęp w różny sposób. Odkryłem, że muszę załadować oryginalną miniaturę, a następnie po pobraniu pełnego rozmiaru obrazu mogę ją zastąpić. Ale nie jestem pewien, jak to zrobić.

tej pory co mam to:

UICollectionview

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    // Do any additional setup after loading the view. 

    self.myCache = [[NSCache alloc] init]; 

} 

//Reusable cell structure 
- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath { 

    //cell 
    CoverPhotoCell *cell = [cv dequeueReusableCellWithReuseIdentifier:@"CoverImgCell" forIndexPath:indexPath]; 
    cell.backgroundColor = [UIColor blackColor]; 
    cell.clipsToBounds = YES; 
    cell.opaque = YES; 
    cell.layer.shouldRasterize = YES; 
    cell.layer.rasterizationScale = [UIScreen mainScreen].scale; 

    Media *object = [[Media alloc] init]; 
    object = [self.photoListArray objectAtIndex:indexPath.item]; 

    //Remove old cell 
    for (UIView *subview in [cell subviews]){ 
     if (subview.tag != 0) 
     { 
      [subview removeFromSuperview]; 
     } 
    } 

    //UIImage 
    UIImage *thumbImg = [_myCache objectForKey:object.url]; 

    if (thumbImg) { 

     cell.imageView.image = thumbImg; 
    } 
    else { 

     cell.imageView.image = nil; 

     UIImage *thumbImg = [[UIImage alloc] initWithCGImage:[object.asset aspectRatioThumbnail]]; 

     dispatch_async(dispatch_get_main_queue(), ^{ 
      cell.imageView.image = thumbImg; 
     }); 

     [_myCache setObject:thumbImg forKey:object.url]; 

    } 

    //thumbnail 
    cell.imageView.tag = indexPath.row + 1; 

    cell.imageView.layer.borderWidth = 5; 
    cell.imageView.layer.borderColor = [UIColor whiteColor].CGColor; 
    cell.imageView.contentMode = UIViewContentModeScaleAspectFit; 

    cell.imageView.frame = CGRectMake(0, 0, 125, 125); 

    return cell; 
} 

//User taps image 
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 
{ 
    if ([segue.identifier isEqualToString:@"PhotoSegue"]) { 
     DetailPageController *controller = segue.destinationViewController; 

     NSIndexPath *selectedIndex = [self.collectionView indexPathsForSelectedItems][0]; 

     controller.initialIndex = (NSUInteger)selectedIndex.item; 

     controller.photos = self.photoListArray; 

    } 
} 

Więc to jest mój kod NSCache, następnie używam segue do pełnego kontrolera widoku, który wyświetla obraz w pełnej rozdzielczości zdjęcia. Jak załadować najpierw miniaturę, a następnie obraz w pełnym rozmiarze.

Także jakaś myśl o tym, jak jabłko ładuje swoje obrazy tak szybko? Czy używają innego sposobu buforowania? Czy robię coś niepoprawnie.

rafinowany Edit:


Czy ktoś poczta lub przynajmniej pkt mnie kierunku niektóre przykładowy kod gdzie mogę pokazać miniatury, gdy użytkownik przewija szybko i załadować rzeczywiste obrazy, kiedy zwolnić, podobnie jak myślę, aplikacja przyczep filmowych jabłek.

+0

* „Trudna część przenosi się do obrazu Duży format Jest to w innym świetle i chciałbym przejścia na zdjęcie Duży format, jak również firmy Apple robi z ich aplikacji Zdjęcia.” * - prawda mieć na myśli konkretny wymiar? * Wygląda na to, że Apple buforuje obrazy i uzyskuje do nich dostęp inaczej Stwierdziłem, że muszę załadować oryginalną miniaturę wtedy, gdy pobierany jest pełnowymiarowy obraz Mogę go zastąpić Ale nie jestem pewien jak zrób to. "* Czy możesz to wyjaśnić? W jaki sposób uzyskują dostęp do niego "inaczej"? Czego nie jesteś pewien? –

Odpowiedz

6

Kompletna odpowiedź z kodem byłaby zbyt duża dla SO. Więc próbuję opisać podstawy:

Powinieneś stworzyć własną pamięć podręczną obrazu. W widoku przewijania strony widoczne są maksymalnie dwa obrazy. Przeglądanie zdjęć w widoku przewijania włączonego stronicowania powoduje, że pamięć podręczna obrazów musi zawierać co najmniej trzy obrazy w pełnym rozmiarze.

Pamięć podręczna działa następująco:

Zakładając, że masz listę obrazów, które mogą być dostępne przez indeks, który odpowiada pozycji w widoku przewijania w „Album Viewer”.

Z bieżącego indeksu (asynchronicznie) obrazów załadować do pamięci podręcznej dla indeksu 1, indeks i indeks + 1, chyba że ten obraz już istnieje w pamięci podręcznej lub indeks jest poza zakresem.

Gdy użytkownik rozpocznie przewijanie następny obraz stanie się widoczny.

Gdy użytkownik przewinie do przodu i przewinął pół strony, bieżący indeks wzrośnie o jeden. W tym momencie widoczne są dwa obrazy - każda połowa. Teraz, gdy indeks się zmienia, rzutuje się obraz z bieżącego indeksu-2 i ładuje następny obraz przy bieżącym indeksie + 1.

Gdy użytkownik przewinie do tyłu, indeks zmniejszy się o jeden. Rzucasz indeks + 2 i ładujesz odpowiedni obraz dla bieżącego indeksu-1.

Możesz poprawić ten schemat, dodając pamięć podręczną widoku kciuka, która działa dokładnie tak, jak powyżej, ale używa szerszego zakresu, np. Ładowanie 20 obrazów z wyprzedzeniem. Użyj obrazów kciuka jako "zastępczych", gdy obraz o pełnym rozmiarze nie jest jeszcze załadowany (uwaga: wszystko będzie asynchroniczne).

Jeśli użytkownik przewinie "szybko", nie ładuj pełnowymiarowych obrazów, po prostu poczekaj, aż prędkość spadnie do określonej wartości. Możesz określić prędkość przewijania z pewnym wysiłkiem.

Jeśli użytkownik przewija bardzo szybko, to nawet obraz kciuka nie jest dostępny, gdy ma być wyświetlany. Następnie użyj statycznego obrazu zastępczego. (Należy również uważać, aby nie zastąpić obrazu o pełnym rozmiarze obrazem kciuka).

+0

Może źle to opisałem, mam już działającą wersję pełnoekranową, jej miniatury utrudniają mi pracę. – lostAstronaut

+0

Na przykład aplikacja Zdjęcia bardzo dobrze przewija duże kolekcje. – lostAstronaut

+1

Powinieneś przeczytać uważniej. Czego NIE powinieneś robić, to ładowanie obrazu, gdy komórka jest widoczna - wtedy jest już za późno. Zamiast tego wystarczy wyświetlić gotowy obraz i asynchronicznie załadować widok _next_ do pamięci podręcznej. Twoje podejście nie jest skalowalne i prawdopodobnie jest to jąkanie. – CouchDeveloper

1

Załadowałbym obrazek z AFNetworking.

Można użyć następującego

[imageView setImageWithURL:[NSURL URLWithString:@"http://i.imgur.com/r4uwx.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder-avatar"]]; 

Można załadować zastępczy jako miniatury i zostanie on zastąpiony innym obrazem po załadowaniu.

http://cocoadocs.org/docsets/AFNetworking/1.3.1/Categories/UIImageView+AFNetworking.html

+0

Podoba mi się twój pomysł, ale moje zdjęcia są pobierane z biblioteki zasobów. – lostAstronaut

+0

Ok, więc użyłbym podobnego podejścia do tego, jak to osiągnąć. Najpierw załaduj odpowiedni widok obrazu z obrazem uchwytu miejsca. Następnie odpal swój wątek w tle (jeśli to konieczne) z blokiem ukończenia, przesyłając obraz z powrotem i aktualizując obraz z podglądem obrazu z nowym raz otrzymanym – StuartM

Powiązane problemy