Главная » iPhone » Переворачивание альбома в стиле Cover Flow iPhone

0

В главе 5 были рассмотрены трансформации Layer Kit, которые позволяют вращать, масштабировать и трансформировать уровень различными способами. Layer Kit является основой для технологии Cover Flow от Apple, которая используется в выборе альбомов из приложения iPod в альбомном режиме.

Лейтон Дункан (Layton Duncan of Polar Bear Farm), разработчик программного обеспечения для iPhone. любезно предоставил пример адаптированного для iPhone кода CovertFlow от Apple (из примеров инструментов Xcode). Исходный код и изображения приложения во всей их полноте можно загрузить с Web-узла "Polar Bear Farm" по адресу: http://www.poIarbearfarni.com.

Мы немного оживили пример Лейтона и использовали фотоальбом iPhone в качестве обложек альбома. Поэтому прежде чем воспользоваться данным примером, убедитесь в том, что вы сделали несколько фотоснимков с помощью вашего iPhone.

Чтобы скомпилировать этот пример из командной строки, воспользуйтесь пакетом инструментов следующим образом:

$ arm-apple-darwin9-gcc -о CovertFlow CovertFlow.m -lobjc ‘Ъ

-framework CoreFoundation -framework Foundation -framework UIKit

-framework QuartzCore -framework CoreGraphics -framework GraphicsServices

Листинги П2 и ПЗ содержат соответствующий код.

#import <Foundation/Foundation.h> #import <CoreFoundation/CoreFoundation.h> #import <UIKit/UIKit.h> #import <UIKit/UIApplication.h> #import <UIKit/UIScroller.h> #import <UIKit/UIView-Hierarchy.h> #import <QuartzCore/QuartzCore.h> #import <QuartzCore/CAScrollLayer.h> #import <GraphicsServices/GraphicsServices.h>

/* Количество прокрученных пикселов,

прежде чем следующая обложка выйдет на передний план */ #define SCROLL PIXELS 60.О

/* Размер каждой обложки */ #define COVER_WIDTH_HEIGHT 128.0

©interface CFView : UlScroller {

BOOL beating;

}

-   (id) initWithFrame:(struct CGRect)frame;

-   (void) mouseDragged:(GSEvent*)event;

-   (void) heartbeatCallback; ©end

©interface CovertFlowApplication : UIApplication {

UlWindow *window; CFView *mainView;

CAScrollLayer *cfIntLayer; NSMutableArray *pictures; int selected;

}

+ (CovertFlowApplication *)sharedlnstance;

-   (void) jumpToCover:(int)index;

-   (void) layoutLayer:(CAScrollLayer *)layer; @end

#import <CoreFoundation/CoreFoundation.h>

#import <Foundation/Foundation.h>

#import <UIKit/CDStructures.h>

#import <UIKit/UlWindow.h>

#import <UIKit/UIView.h>

#inport <UIKit/UIView-Hierarchy.h>

#import <UIKit/UIHardware.h>

#import <UIKit/UIResponder.h>

#import <GraphicsServices/GraphicsServices.h>

It import <UIKit/UIView-Geometry.h>

ttimport <CoreGraphics/CGGeometry.h>

#import <UIKit/UIKit.h>

#import <QuartzCore/QuartzCore.n>

#import <QuartzCore/CALayer.h>

#import <QuartzCore/CAScrollLayer.h>

#import <QuartzCore/CAAnimation.h>

#import <QuartzCore/CATransition.h>

# import <Quart zCore/CATransact ion.h>

#import <QuartzCore/CAMediaTimingFunction.h>

#import "Cov6rtFlow.h"

#import "math.h"

static CovertFlowApplication *sharedlnstance;

int main(int argc, char **argv)

{

NSAutoreleasePool *autoreleasePool = [ [ NSAutoreleasePool alloc ] init

];

int returnCode = UIApplicationMain(argc, argv,

@"CovertFlowApplication", @"CovertFlowApplication"); [ autoreleasePool release ]; return returnCode;

)

@ implementation CFView

-(id)initwithFrame:(struct CGRect)frame {

self = [ super initwithFrame: frame ]; if (nil != self) {

[self setTapDelegate:self]; [self setDelegate:self]; beating = NO;

[ self startHeartbeat: @selector(heartbeatCallback) inRunLoopMode:nil ];

}

return self;

}

- (void) mouseDragged:(GSEvent*)event {

if (beating == NO) {

/* Пользователь начал пролистывать обложки. Начинаем момент обновления coverflow */

beating = YES;

[ self startHeartbeat: Gselector(heartbeatCallback) i nRun LoopMode:n i1 ];

}

[ super mouseDragged: event ];

-   (void)heartbeatCallback {

[ [ CovertFlowApplication sharedlnstance ]

jumpToCover:(int) roundf(([ self offset ].y/SCROLL_PIXELS))

] ;

if (! [self isScrolling] ) {

/* Останавливаем момент обновления,

когда останавливается прокрутка */ [ self stopHeartbeat: @selector(heartbeatCallback) ]; beating = NO;

)

}

@end

@implementation CovertFlowApplication

+ (CovertFlowApplication *)sharedlnstance

{

if (!sharedlnstance) {

sharedlnstance = [ [ CovertFlowApplication alloc ] init ];

}

return sharedlnstance;

}

-   (void)applicationDidFinishLaunching:(NSNotification *)aNotification {

UIImageView *background; CGRect rect; NSString *file, *path; NSDirectoryEnumerator *dirEnum; int i, j;

/* Читаем папку изображений */ path = [ [ NSString alloc ] initWithString: @"/var/mobile/Media/DCIM/100APPLE" ];

pictures = [ [ NSMutableArray alloc] init ];

dirEnum = [ [ NSFileManager defaultManager ] enumeratorAtPath: path ];

while ((file = [ dirEnum nextObject ])) {

if ( [ [ file pathExtension ] isEqualToString: @"THM" ]) {

[ pictures addObject: [ [ NSString alloc ] initWithString: [ path stringByAppendingPathComponent: file ] ] J;

}

}

j = [ pictures count ];

window = [ [ UlWindow alloc ] initWithContentRect:

[ UIHardware fullScreenApplicationContentRect ] ] ;

rect = [ UIHardware fullScreenApplicationContentRect ]; rect.origin.x = rect.origin.у = O.Of;

sharedlnstance = self;

mainView = [ [ CFView alloc ] initWithFrame: rect ];

/* Задаем # пикселов для перетаскивания до того, как прокрутка начнет перемещение */ [ mainView setScrollHysteresis: 64.0 ];

/* Запрещаем эффект резиновой ленты */ [ mainView setА1lowsFourWayRubberBanding: NO ];

/* Это приводит к тому, что прокрутка становится более жесткой */ [ mainView setScrollDecelerationFactor: 0.9999 ];

/* Задаем прокручиваемый вид,

чтобы перескочить к пиксельным границам */ [ mainView setGridSize:CGSizeMake(SCROLL PIXELS, SCROLL PIXELS) ];

[ window setContentView: mainView ]; [ window orderFront: self ]; [ window makeKey: self ]; [ window setHidden: NO ] ;

/* Инициализируем уровень CovertFlow */

cflntLayer = [ [ CAScrollLayer alloc ] initWithBounds:

CGRectMake(0, 0, rect.size.width, rect.size.height + 128)

];

[ cflntLayer setDelegate:self J;

/* Размещаем уровень CovertFlow в средине прокручиваемого вида */ cflntLayer.position = CGPointMake(160, 304); [ cflntLayer setDelegaterself ];

/* Загружаем обложки альбомов */ for (i=0; i<j; i++) {

NSString *filename = [ pictures objectAtIndex: i ];

background = [ [ [ UIImageView alloc ] initwithFrame:

CGRectMake(0, 0, COVER_WIDTH_HEIGHT, COVER_WIDTH_HEIGHT)

]

autorelease

] ;

[ background setlmage: [ [ Ullmage alloc ]

initWithContentsOfFile: filename ) ]; [ cflntLayer addSublayer: [ background _layer ] ];

}

/* Задаем размер прокручиваемого вида пропорционально # обложек */ ( mainView setContentSize:

CGSizeMake(320, ( (rect.size.height) + (SCROLL_PIXELS*j) ) )

];

/* Добавляем уровень альбома в основной уровень */ selected = 0;

[ [ mainView _layer ] addSublayer:cfIntLayer ]; [ self layoutLayer: cflntLayer ];

}

- (void) jumpToCover:(int)index {

if (index != selected) { selected = index; [ self layoutLayer:cflntLayer ];

}

}

-(void) layoutLayer:(CAScrollLayer *)layer {

CALayer *sublayer;

NSArray *array;

size_t i, count;

CGRect rect, cflmageRect;

NSSize cellSize, spacing, margin;

CGSize size;

CATransform leftTransform, rightTransform, sublayerTransform;

float zCenterPosition, zSidePosition;

float sideSpacingFactor, rowScaleFactor;

float angle = 1.39;

int x;

size = [ layer bounds j.size;

zCenterPosition =60; /* Положение Z выделенной обложки */ zSidePosition =0; /* Положение Z по умолчанию для других обложек */ sideSpacingFactor = .85; /* Насколько близко должны быть

обложки слайдов */ rowScaleFactor = .55; /* Расстояние между основной обложкой

и обложками сторон */

leftTransform=CATransform3DMakeRotation(angle, -1,0,0) ; rightTransform = CATransform3DMakeRotation(-angle,-1, 0, 0);

margin = NSMakeSize(5.О, 5.0); spacing = NSMakeSize(5.0, 5.0);

cellSize = NSMakeSize (COVER_WIDTH_HEIGHT, COVER_WIDTH_HEIGHT);

margin.width += (size.width – cellSize.width * [ pictures count ] -

spacing.width * ([ pictures count ] – 1)) * .5; margin.width = floor (margin.width);

/* Строим массив обложек */ array = [ layer sublayers ]; count = [ array count ];

sublayerTransform = CATransform3DIdentity; /* Задаем перспективу */ sublayerTransform.m34 = -0.006;

/* Начинаем CATransaction, чтобы все анимации

выполнились одновременно */ [ CATransaction begin ];

[ CATransaction setValue: [ NSNumber numberWithFloat:0.3f ] forKey:@"animationDuration" ];

for (i =0; i < count; i++) {

sublayer = [ array objectAtIndex:i ]; x = i;

rect.size = MCGSize *)&cellSize; rect.origin = CGPointMake(0,0); cflmageRect = rect;

/* Основное размещение */

rect.origin.x = size.width / 2 – cellSize.width / 2; rect.origin.у = margin.height +

x * (cellSize.height + spacing.height);

[ [ sublayer superlayer ] setSublayerTransform: sublayerTransform ];

if (x < selected) /* Левая сторона */ {

rect.origin.у += cellSize.height * sideSpacingFactor *

(float) (selected – x – rowScaleFactor); sublayer.zPosition = zSidePosition – 2.0 * (selected – x); sublayer.transform = leftTransform;

)

else if (x > selected) /* Правая сторона */ {

rect.origin.у -= cellSize.height * sideSpacingFactor

* (float) (x – selected – rowScaleFactor); sublayer.zPosition = zSidePosition – 2.0 * (x – selected); sublayer.transform = rightTransform;

}

else /* Выбранная обложка */ {

sublayer.transform = CATransform3DIdentity; Cover Flow-Style Album Flipping | 243

sublayer.zPosition = zCenterPosition; /* Размещаем посередине прокручиваемого вида */ [ layer scrollToPoint: CGPointMake(0, rect.origin.у -

(([ layer bounds ].size.height – cellSize.width)/2.0))

];

/* Размещаем прокручиваемый уровень в центре вида */ layer.position =

CGPointMake(160.Of, 240.Of + (selected * SCROLL_PIXELS));

}

[ sublayer setFrame: rect ];

}

[ CATransaction commit ];

}

@end

Как это работает

1.     При порождении приложения вызывается его метод

applicationDidFinishLaunching.

2.     Сначала этот метод пробегает по папке альбомов iPhone и проводит опись всех изображений пиктограмм. Затем он инициализирует новое окно и подклассивизирует вид uiscroller под именем CFView в объект mainView. Здесь определяются различные свойства прокручиваемого вида.

3.     Каждая пиктограмма фотоальбома загружается в объект ui image, а затем присваивается уровню. Когда приложение завершает инициализацию, вызывается метод layoutLayer.

4.      Метод layoutLayer размещает каждый уровень в виде в соответствии с его положением. Выделенный альбом переносится на передний план, а остальные поворачиваются с помощью методов rightTransforrn и

leftTransform объектов CATransform.

5.     Когда пользователь перемещает свой палец, вызывается метод mouseDragged. В результате чего выбирается новая обложка и снова вызывается layoutLayers.

6.      Чтобы убедиться в том, что все объекты анимируются одновременно, создается CATransaction. Недавно выделенный альбом поворачивается к лицевой стороне экрана. Когда транзакция совершится, платформа Layer Kit выполнит все построения промежуточных изображений таким образом, что они автоматически произойдут за заданный для анимации временной интервал (0,03 с).

 

Источник: Здзиарски Дж. iPhone. Разработка приложений с открытым кодом: Пер„с англ. — 2-е изд., перераб. и доп. — СПб.: БХВ-Петербург, 2009. — 368 е.: ил.

По теме:

  • Комментарии