<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Roger Boesch &#187; Cover Flow</title>
	<atom:link href="http://www.rogerboesch.com/tag/cover-flow/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.rogerboesch.com</link>
	<description>iOS Warrior</description>
	<lastBuildDate>Mon, 22 Nov 2010 20:04:34 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>CoverFlow</title>
		<link>http://www.rogerboesch.com/2009/08/16/coverflow-programmieren/</link>
		<comments>http://www.rogerboesch.com/2009/08/16/coverflow-programmieren/#comments</comments>
		<pubDate>Sun, 16 Aug 2009 16:05:40 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Cover Flow]]></category>
		<category><![CDATA[OpenGL]]></category>

		<guid isPermaLink="false">http://www.rogerboesch.com/?p=611</guid>
		<description><![CDATA[Bereits Anfang des Jahres habe ich einen Blog Beitrag zum Thema Cover Flow geschrieben. Ein Thema, zu dem mich seither immer wieder Mails und Anfragen erreicht haben. Insbesondere für Entwickler, die noch nicht so lange mit Objective-C und Cocoa entwickeln ist das Thema zugegebenermassen auch nicht ganz ohne. Möchte man einen Cover Flow in eine [...]]]></description>
			<content:encoded><![CDATA[<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="425" height="344" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube.com/v/zSsns24bUPo&amp;hl=en&amp;fs=1&amp;" /><param name="allowfullscreen" value="true" /><embed type="application/x-shockwave-flash" width="425" height="344" src="http://www.youtube.com/v/zSsns24bUPo&amp;hl=en&amp;fs=1&amp;" allowscriptaccess="always" allowfullscreen="true"></embed></object><br />
Bereits Anfang des Jahres habe ich einen Blog Beitrag zum Thema Cover Flow geschrieben. Ein Thema, zu dem mich seither immer wieder Mails und Anfragen erreicht haben. Insbesondere für Entwickler, die noch nicht so lange mit Objective-C und Cocoa entwickeln ist das Thema zugegebenermassen auch nicht ganz ohne.<br />
Möchte man einen Cover Flow in eine eigene App einbauen gibt es zunächst drei Möglichkeiten:</p>
<ul>
<li> Man benutzt den Cover Flow View aus den Private Frameworks von Apple (Keine gute Idee, wenn man die App später auch erfolgreich in den AppStore bringen möchte)</li>
<li> Man benutzt Core Animation und Layers</li>
<li> Man verwendet OpenGL</li>
</ul>
<p>Auf die erste Möglichkeit gehe ich aus verständlichen Gründen nicht weiter ein. Die zweite Variante mit Core Animation kam in einem meiner recht frühen Projekte zum Einsatz (Den Beispielcode erläutere ich nacholgend) und hat sich gut bewährt. Variante 3 setze ich aktuell in den Projekten ein, kann als Library gekauft werden und ist zudem im Video zu sehen.</p>
<p>Da das Core Animation Framework auf dem iPhone nicht ganz so mächtig wie unter MacOSX ist, muss man auf Filter verzichten, trotzdem sind schöne Ergebnisse zu erzielen. Doch nun zum Code.</p>
<pre lang="objc">#import
#import 

@protocol RBCoverFlowDelegate
- (int)numberOfItems;
- (UIImage*)coverImageForIndex:(int)index;
- (UIImage*)placeholderImage;
- (void)coverHasChangedToIndex:(int)index;
- (void)clickOnCoverWithIndex:(int)index;
@end

@interface RBCoverFlowView : UIView {
	CGPoint _startTouchPosition;
	float _centerPosition;
	float _sidePosition;
	CATransform3D _leftTransform;
	CATransform3D _rightTransform;

	CALayer* _contentLayer;

	id _delegate;
	int _itemCount;

	CGImageRef _placeholderImageRef;
	UIImage* _placeholderImage;
	CGImageRef _maskedPlaceholderImageRef;

	CGSize _imageSize;
	CGFloat _imageScaleX;
	CGFloat _imageScaleY;

	float _rowScaleFactor;
}

// Start the cover flow
- (void)start:(id)delegate;

@end
</pre>
<p>Der Cover Flow besteht zunächst aus einem &#8220;Hauptview&#8221;, der von UIView abgeleitet ist und in dem die Covers dargestellt werden. Dieser ist zudem für das Verarbeiten der Touches und der gesamten Animation zuständig.</p>
<p>Die Covers selber bestehen aus einzelnen Layern, bzw. genau drei Layern pro Cover. Der Layer mit dem Bild selber, ein Layer, der die Spiegelung (Reflection) darstellt und ein Rahmen-Layer, der das ganze Cover umschliesst.</p>
<pre lang="objc">- (CALayer *)addCoverLayer:(int)index {
	CALayer* containerLayer = [CALayer layer];
	containerLayer.name = [NSString stringWithFormat:@"%d", index];
	containerLayer.frame = CGRectMake(0.0f, 0.0f, [[self maxAvalibleImageWidth] floatValue], 1.5f * [[self maxAvalibleImageHeight] floatValue]);
	containerLayer.contentsGravity = kCAGravityResize;

	CALayer* holderLayer = [CALayer layer];
	holderLayer.name = [NSString stringWithFormat:@"Holder_%d", index];
	holderLayer.frame = CGRectMake(0.0f, 0.0f, [[self maxAvalibleImageWidth] floatValue], 1.5 * [[self maxAvalibleImageHeight] floatValue]);
	holderLayer.contentsGravity = kCAGravityResize;

	CALayer* imageLayer = [CALayer layer];
	imageLayer.name = [NSString stringWithFormat:@"Image_%d", index];
	imageLayer.contents = (id)_placeholderImageRef;
	imageLayer.frame = [self imageRect:(CGImageRef)imageLayer.contents];
	imageLayer.contentsGravity = kCAGravityResizeAspectFill;
	imageLayer.masksToBounds = YES;

	CALayer* reflectionLayer = [CALayer layer];
	reflectionLayer.name = [NSString stringWithFormat:@"Reflection_%d", index];
	reflectionLayer.contents = (id)_maskedPlaceholderImageRef;
	CGRect frame = [self imageRect:(CGImageRef)reflectionLayer.contents];
	frame.origin.y = imageLayer.frame.size.height + 2;
	reflectionLayer.frame = frame;
	reflectionLayer.contentsGravity = kCAGravityResize;
	reflectionLayer.masksToBounds = YES;
	reflectionLayer.transform = CATransform3DMakeScale(1.0f, -1.0f, 1.0f);
	reflectionLayer.opacity = 0.6;

	[containerLayer setValue:imageLayer forKey:kImageLayerKey];
	[containerLayer setValue:reflectionLayer forKey:kImageReflectionKey];
	[containerLayer setValue:holderLayer forKey:kImageHolderKey];

	[holderLayer addSublayer:imageLayer];
	[holderLayer addSublayer:reflectionLayer];
	[containerLayer addSublayer:holderLayer];

	return containerLayer;
}
</pre>
<p>Sind die Layer erstellt worden, müssen die einzelnen Cover nun entsprechend positioniert werden, damit das Aussehen dem Cover Flow der iPod App entspricht. Dies erreicht man, in dem man jeden einzelnen Layer im Raum positioniert, skaliert und leicht dreht.</p>
<pre lang="objc">- (void)layoutSublayer:(CALayer*)rootLayer number:(int)number {
	int selectedIndex = [[_contentLayer valueForKey:@"selectedIndex"] integerValue];

	rootLayer.frame = CGRectMake(0.0f, 0.0f, [[self maxAvalibleImageWidth] floatValue], 1.5f * [[self maxAvalibleImageHeight] floatValue]);

	CATransform3D layerTransform = CATransform3DIdentity;
	layerTransform.m34 = 1.0f / _sidePosition;

	CALayer* holder = [rootLayer valueForKey:kImageHolderKey];

	CGPoint pos = CGPointMake(CGRectGetMidX(_contentLayer.bounds), CGRectGetMidY(_contentLayer.bounds));

	if (number &lt; selectedIndex) {
		pos.x -= (selectedIndex - number) * _imageSize.width * _rowScaleFactor;
		holder.transform = _leftTransform;
		holder.zPosition = _sidePosition;
		rootLayer.zPosition = _sidePosition - 0.1f * (selectedIndex - number);
		rootLayer.sublayerTransform = layerTransform;
	} else if (number &gt; selectedIndex) {
		pos.x += (number - selectedIndex) * _imageSize.width * _rowScaleFactor;
		holder.transform = _rightTransform;
		holder.zPosition = _sidePosition;
		rootLayer.zPosition = _sidePosition - 0.1f * (number - selectedIndex);
		rootLayer.sublayerTransform = layerTransform;
	} else {
		pos.x = (self.bounds.size.width - _imageSize.width) / 2;
		holder.transform = CATransform3DIdentity;
		holder.zPosition = _centerPosition;
		holder.filters = nil;
		rootLayer.zPosition = _centerPosition;
		rootLayer.sublayerTransform = CATransform3DIdentity;
	}

	rootLayer.position = pos;
}
</pre>
<p>Die Animation ist in dem Code (Hier sind die kompletten <a href="http://www.rogerboesch.com/tutorials/CoverFlowSource.zip">Source Files</a>) bewusst recht einfach gehalten und unterstützt keine sogenannten Heartbeat Animationen, d.h. Animationen die sogleich beginnen, wenn der Finger aufgesetzt wird. Im käuflichen und auf OpenGL basierten Code ist dies selbstverständlich vorhanden und insbesondere das Laden und Aufbauen der Bilder noch stark optimiert. Aber als Einstieg und fürs bessere Verständnis hoffe ich, dass der Beispielcode hier erstmal weiterhilft. Wer mehr darüber erfahren möchte, dem möchte ich nochmals unsere <a href="http://www.rogerboesch.com/workshops/">Workshops</a> ans Herz legen, in denen wir wesentlich tiefer in die Materie einsteigen können. Also, viel Spass beim Cover Flow programmieren und nicht vergessen, auf mein Blog zu verlinken wenn Ihr die erste iApp mit Cover Flow in den Appstore bringt <img src='http://www.rogerboesch.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><em>Anfangs basierte dieser Code übrigens auf einem Beispiel Code von <a title='Original Link: http://bill.dudney.net/roller/objc/'  href="http://www.rogerboesch.com/?1haoVHxh">Bill Dudney</a>, der damals einen Artikel über die Programmierung eines Cover Flow unter MacOSX veröffenlichte und auch ein sehr gut geschriebenes Buch zum Thema Core Animation geschrieben hat.</em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.rogerboesch.com/2009/08/16/coverflow-programmieren/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>CoverFlow View (selber) programmieren</title>
		<link>http://www.rogerboesch.com/2008/11/16/coverflow-view-selber-programmieren/</link>
		<comments>http://www.rogerboesch.com/2008/11/16/coverflow-view-selber-programmieren/#comments</comments>
		<pubDate>Sun, 16 Nov 2008 08:02:19 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Code snippet]]></category>
		<category><![CDATA[Core Animation]]></category>
		<category><![CDATA[Cover Flow]]></category>

		<guid isPermaLink="false">http://www.rogerboesch.com/?p=84</guid>
		<description><![CDATA[Für ein aktuelles iPhone Projekt benötigte ich dringend ein CoverFlow View. Aber genau danach sucht man auf den Apple Entwickler Seiten, im Beispielcode und auch in Google Search mehr oder weniger vergebens. Blieb also nichts anderes übrig, als so ein Custom View selber zu schreiben. Der grösste Vorteil dabei ist das von Mac OSX her [...]]]></description>
			<content:encoded><![CDATA[<p>Für ein aktuelles iPhone Projekt benötigte ich dringend ein CoverFlow View. Aber genau danach sucht man auf den Apple Entwickler Seiten, im Beispielcode und auch in Google Search mehr oder weniger vergebens. Blieb also nichts anderes übrig, als so ein Custom View selber zu schreiben. Der grösste Vorteil dabei ist das von Mac OSX her bereits bekannte Core Animation Framework, das es in (fast) identischer Form auch für&#8217;s iPhone gibt. Theoretisch sollte eine Umsetzung also relativ einfach sein&#8230; War es dann eigentlich auch, mit einigen ganz kleinen Hürden, die sich zwischendurch ergaben. Bei einem solchen Vorhaben hat sich bei mir immer das folgende Vorgehen bewährt.</p>
<p>Zerlegen des gesamten Control&#8217;s in die einzelnen Bestandteile (Layer, Subviews, Aufbau etc.). Macht man das für ein CoverFlow, so besteht dieses prinzipiell aus zwei Komponten:</p>
<p>Zum einen aus dem View selber (in dem sich das Geschehen abspielen soll) und zum anderen aus einzelnen Covers (oder generell Images), die mehrfach vorkommen, ein Bild enthalten und sich an drei Positionen befinden kann. Das einzelne Cover wiederum besteht aus dem Bild selber und einem Spiegelbild (Reflection). Bisher also alles Komponenten, die im iPhone SDK vorhanden sind. Das einzige was nicht standardmässig vorhanden ist, ist die Reflection, zudem fehlen hier die von Mac OSX bekannten Filter. Aber das lässt sich umgehen. Die Struktur des Controls (und damit auch der Aufbau der Klasse) wäre nun also soweit klar und ist in nachfolgender Abbildung noch ein wenig genauer (technisch detaillierter) abgebildet.</p>
<p>Der Code, der notwendig ist, um den View zum Leben zu erwecken, könnte also wie folgender Pseudocode aussehen:</p>
<pre lang="text">for all images {
 create a cover layer {
  create an image layer and add it to the cover layer
  create a reflection layer and add it to the cover layer {
   add a reversed image
   add a gradient
  }
 }
}

Position the cover layer at left, center or right position

if (cover is at left or right position) {
  make a transformation of the cover view
  re-position each cover
  transformation again
}</pre>
<p>Eigentlich ganz einfach oder? Ich hoffe, dass die Gedankengänge nachvollziehbar sind und genug Anregung bieten, einen CoverFlow View selber zu programmieren.  Auf das eine oder andere Thema werde ich in künftigen Einträgen sicher noch ein wenig näher eingehen. Viel Spass beim nachprogrammieren!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.rogerboesch.com/2008/11/16/coverflow-view-selber-programmieren/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

