用Hadoop进行分布式数据处理,第1部分 入门

| 收藏本文 下载本文 作者:开心龙

下面是小编整理的用Hadoop进行分布式数据处理,第1部分 入门(共含7篇),欢迎您能喜欢,也请多多分享。同时,但愿您也能像本文投稿人“开心龙”一样,积极向本站投稿分享好文章。

用Hadoop进行分布式数据处理,第1部分 入门

篇1:用Hadoop进行分布式数据处理,第1部分 入门

尽管 Hadoop 是一些大型搜索引擎数据缩减功能的核心部分,但是它实际上 是一个分布式数据处理框架,搜索引擎需要收集数据,而且是数量极大的数据。 作为分布式框架,Hadoop 让许多应用程序能够受益于并行数据处理。

本文并不打算介绍 Hadoop 及其架构,而是演示一个简单的 Hadoop 设置。现在 ,我们来讨论 Hadoop 的安装和配置。

初始设置

对于本文中的 示例,我们使用 Cloudera Hadoop 发行版。Cloudera 提供对各种 Linux® 发行版的支持,所以很适合初学者。

本文假设您的系统上已经安装了 Java™(至少是 1.6 版)和 cURL。如果还没有,需要先安装它们。

因为我运行 Ubuntu(Intrepid 版),所以使用 apt 实用程序获取 Hadoop 发行版。这个过程非常简单,我可以获取二进制包,而不需要下载并构建源代码 。首先,告诉 apt Cloudera 站点的信息。然后,在 /etc/apt/sources.list.d/cloudera.list 中创建一个新文件并添加以下文本:

deb archive.cloudera.com/debian intrepid-cdh3 contrib

deb-src archive.cloudera.com/debian intrepid- cdh3 contrib

如果您运行 Jaunty 或其他版本,只需把 intrepid 替换为您的版本名(当前支持 Hardy、Intrepid、Jaunty、Karmic 和 Lenny)。

接下来,从 Cloudera 获取 apt-key 以检查下载的包:

$ curl -s archive.cloudera.com/debian/archive.key |

sudo apt -key add - sudo apt-get update

然后,安装采用伪分布式配置的 Hadoop(所有 Hadoop 守护进程在同一个主 机上运行):

$ sudo apt-get install hadoop-0.20-conf-pseudo

$

注意,这个配置大约 23MB(不包括 apt 可能下载的其他包)。这个配置非 常适合体验 Hadoop 以及了解它的元素和界面。

最后,我设置了不需要密码的 SSH。如果打算使用 ssh localhost 并请求密 码,就需要执行以下步骤。我假设这是专用的 Hadoop 机器,因为这个步骤对安 全性有影响(见清单 1)。

清单 1. 设置不需要密码的 SSH

$ sudo su -

# ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa

# cat ~/.ssh/id_dsa.pub >> ~/.ssh/authorized_keys

最后,需要确保主机上有供 datanode使用的足够存储空间(缓存)。存储空 间不足会导致系统表现异常(比如出现无法把数据复制到节点的错误)。

启动 Hadoop

现在可以启动 Hadoop 了,这实际上要启动每个 Hadoop 守护进程。但是, 首先使用 hadoop 命令对 Hadoop File System (HDFS) 进行格式化。hadoop 命 令有许多用途,稍后讨论其中一部分。

首先,请求 namenode 对 DFS 文件系统进行格式化。在安装过程中完成了这 个步骤,但是了解是否需要生成干净的文件系统是有用的。

# hadoop-0.20 namenode -format

在确认请求之后,文件系统进行格式化并返回一些信息。接下来,启动 Hadoop 守护进程。Hadoop 在这个伪分布式配置中启动 5 个守护进程: namenode、secondarynamenode、datanode、jobtracker 和 tasktracker。在启 动每个守护进程时,会看到一些相关信息(指出存储日志的位置)。每个守护进 程都在后台运行。图 1 说明完成启动之后伪分布式配置的架构。

图 1. 伪分布式 Hadoop 配置

Hadoop 提供一些简化启动的辅助工具。这些工具分为启动(比如 start-dfs )和停止(比如 stop-dfs)两类。下面的简单脚本说明如何启动 Hadoop 节点 :

# /usr/lib/hadoop-0.20/bin/start-dfs.sh

# /usr/lib/hadoop-0.20/bin/start-mapred.sh

#

要想检查守护进程是否正在运行,可以使用 jps 命令(这是用于 JVM 进程 的 ps 实用程序)。这个命令列出 5 个守护进程及其进程标识符。

既然 Hadoop 守护进程已经在运行了,现在看看每个守护进程在 Hadoop 框 架中的作用。namenode 是 Hadoop 中的主服务器,它管理文件系统名称空间和 对集群中存储的文件的访问。还有一个 secondary namenode,它不是 namenode 的冗余守护进程,而是提供周期检查点和清理任务。在每个 Hadoop 集群中可以 找到一个 namenode 和一个 secondary namenode。

datanode 管理连接到节点的存储(一个集群中可以有多个节点)。每个存储 数据的节点运行一个 datanode 守护进程。

最后,每个集群有一个 jobtracker,它负责调度 datanode 上的工作。每个 datanode 有一个 tasktracker,它们执行实际工作。jobtracker 和 tasktracker 采用主-从形式,jobtracker 跨 datanode 分发工作,而 tasktracker 执行任务。jobtracker 还检查请求的工作,如果一个 datanode 由于某种原因失败,jobtracker 会重新调度以前的任务。

在这个简单的配置中,所有节点都驻留在同一个主机上(见 图 1)。但是, 通过前面的讨论很容易看出 Hadoop 如何提供并行处理。尽管架构很简单,但是 Hadoop 能够方便地实现数据分发、负载平衡以及以容错的方式并行处理大量数 据。

检查 HDFS

可以通过几个检查确认 Hadoop(至少是 namenode)已经启动并正常运行。 确认所有进程都在运行之后,可以使用 hadoop 命令检查本地名称空间(见清单 2)。

清单 2. 检查对 HDFS 的访问

# hadoop-0.20 fs -ls /

Found 2 items

drwxr-xr-x - root supergroup 0 -04-29 16:38 /user

drwxr-xr-x - root supergroup 0 2010-04-29 16:28 /var

#

可以看出 namenode 已经启动,能够为本地名称空间提供服务。注意,使用 hadoop-0.20 命令检查文件系统。这个实用程序用于与 Hadoop 集群交互,包括 检查文件系统、在集群中运行作业等等。请注意命令的结构:指定 hadoop-0.20 实用程序之后,定义一个命令(在这里是通用文件系统 shell)以及一个或多个 选项(在这里使用 ls 请求文件列表)。因为 hadoop-0.20 是 Hadoop 集群的 主要接口之一,您会看到本文中多次使用这个实用程序。清单 3 提供另外几个 文件系统操作示例(创建子目录 test,列出它的内容,然后删除它),可以通 过它们进一步了解这个接口。

清单 3. Hadoop 中的文件系统操作

# hadoop-0.20 fs -mkdir test

# hadoop-0.20 fs -ls test

# hadoop-0.20 fs -rmr test

Deleted hdfs://localhost/user/root/test

#

测试 Hadoop

既然已经安装了 Hadoop 并测试了文件系统的基本接口,现在就该在真实的 应用程序中测试 Hadoop 了。在这个示例中,我们使用 MapReduce 处理一个小 数据集。map(映射) 和 reduce(缩减) 源自函数式编程中的函数名,但是这 个应用程序的核心功能是数据缩减。映射 是指把大量输入处理成更小的子问题 集(然后把这些子问题分发给并行的工作系统)。缩减 是指把子问题的答案组 合成单一输出集。注意,这里没有定义处理 的含义,因为框架允许您自己定义 什么是处理。典型的 MapReduce 示例是计算单词在文档集中出现的频率。

根据前面的讨论,我们需要一个输入集并产生一个输出集。第一步是在文件 系统中创建一个 input 子目录,工作将放在这个目录中。使用以下命令:

# hadoop-0.20 fs -mkdir input

接下来,在 input 目录中放一些工作。在这里,使用 put 命令把文件从本 地文件系统转移到 HDFS 中(见清单 4)。注意,下面的命令格式把源文件转移 到 HDFS 子目录 (input) 中。完成之后,在 HDFS 中就有两个文本文件等待处 理。

清单 4. 把文件转移到 HDFS 中

# hadoop-0.20 fs -put /usr/src/linux-source- 2.6.27/Doc*/memory-barriers.txt input

# hadoop-0.20 fs -put /usr/src/linux-source-2.6.27/Doc*/rt- mutex-design.txt input

#

接下来,使用 ls 命令检查文件是否存在(见清单 5)。

清单 5. 检查 HDFS 中的文件

# hadoop-0.20 fs -ls input

Found 2 items

-rw-r--r-- 1 root supergroup 78031 2010-04-29 17:35 /user/root/input/memory-barriers.txt

-rw-r--r-- 1 root supergroup 33567 2010-04-29 17:36 /user/root/input/rt-mutex-design.txt

#

确认工作已经放在 HDFS 中之后,就可以执行 MapReduce 函数了。这个函数 只需要一个命令,但是需要很长的请求,见清单 6。这个命令请求执行一个 JAR 。它实际上实现许多功能,但是这个示例只使用 wordcount。jobtracker 守护 进程请求 datanode 执行 MapReduce 作业,这会产生相当多的输出(这里的输 出比较少是因为只处理两个文件)。它显示 map 和 reduce 函数的进度,然后 提供与文件系统的 I/O 和记录处理相关的统计数据。

清单 6. 执行计算单词频率的 MapReduce 作业

# hadoop-0.20 jar /usr/lib/hadoop-0.20/hadoop-0.20.2+228- examples.jar

wordcount input output

10/04/29 17:36:49 INFO input.FileInputFormat: Total input paths to process : 2

10/04/29 17:36:49 INFO mapred.JobClient: Running job: job_201004291628_0009

10/04/29 17:36:50 INFO mapred.JobClient: map 0% reduce 0%

10/04/29 17:37:00 INFO mapred.JobClient: map 100% reduce 0%

10/04/29 17:37:06 INFO mapred.JobClient: map 100% reduce 100%

10/04/29 17:37:08 INFO mapred.JobClient: Job complete: job_201004291628_0009

10/04/29 17:37:08 INFO mapred.JobClient: Counters: 17

10/04/29 17:37:08 INFO mapred.JobClient: Job Counters

10/04/29 17:37:08 INFO mapred.JobClient: Launched reduce tasks=1

10/04/29 17:37:08 INFO mapred.JobClient: Launched map tasks=2

10/04/29 17:37:08 INFO mapred.JobClient: Data-local map tasks=2

10/04/29 17:37:08 INFO mapred.JobClient: FileSystemCounters

10/04/29 17:37:08 INFO mapred.JobClient: FILE_BYTES_READ=47556

10/04/29 17:37:08 INFO mapred.JobClient: HDFS_BYTES_READ=111598

10/04/29 17:37:08 INFO mapred.JobClient: FILE_BYTES_WRITTEN=95182

10/04/29 17:37:08 INFO mapred.JobClient: HDFS_BYTES_WRITTEN=30949

10/04/29 17:37:08 INFO mapred.JobClient: Map-Reduce Framework

10/04/29 17:37:08 INFO mapred.JobClient: Reduce input groups=2974

10/04/29 17:37:08 INFO mapred.JobClient: Combine output records=3381

10/04/29 17:37:08 INFO mapred.JobClient: Map input records=2937

10/04/29 17:37:08 INFO mapred.JobClient: Reduce shuffle bytes=47562

10/04/29 17:37:08 INFO mapred.JobClient: Reduce output records=2974

10/04/29 17:37:08 INFO mapred.JobClient: Spilled Records=6762

10/04/29 17:37:08 INFO mapred.JobClient: Map output bytes=168718

10/04/29 17:37:08 INFO mapred.JobClient: Combine input records=17457

10/04/29 17:37:08 INFO mapred.JobClient: Map output records=17457

10/04/29 17:37:08 INFO mapred.JobClient: Reduce input records=3381

处理结束之后,检查结果,

这个作业的作用是计算单词在输入文件中出现的 次数。输出是一个包含元组的文件,元组表示单词和它在输入中出现的次数。找 到输出文件之后,可以通过 hadoop-0.20 实用程序使用 cat 命令查看数据(见 清单 7)。

清单 7. 检查 MapReduce wordcount 操作的输出

# hadoop-0.20 fs -ls /user/root/output

Found 2 items

drwxr-xr-x - root supergroup 0 2010-04-29 17:36 /user/root/output/_logs

-rw-r--r-- 1 root supergroup 30949 2010-04-29 17:37 /user/root/output/part-r-00000

#

# hadoop-0.20 fs -cat output/part-r-00000 | head -13

!= 1

“Atomic 2

”Cache 2

“Control 1

”Examples 1

“Has 7

”Inter-CPU 1

“LOAD 1

”LOCK“ 1

”Locking 1

“Locks 1

”MMIO 1

“Pending 5

#

还可以使用 hadoop-0.20 实用程序从 HDFS 中提取文件(见清单 8)。只需 使用 get 实用程序(它与前面在 HDFS 中写文件所用的 put 相似)。对于 get 操作,指定 HDFS 中要提取的文件(来自 output 子目录)和在本地文件系统中 要写的文件 (output.txt)。

清单 8. 从 HDFS 提取输出

# hadoop-0.20 fs -get output/part-r-00000 output.txt

# cat output.txt | head -5

!= 1

”Atomic 2

“Cache 2

”Control 1

“Examples 1

#

我们再来看一个示例,它使用相同的 JAR,但是目的不同(在这里要试验并 行的 grep)。对于这个测试,仍然使用现有的输入文件,但是要删除 output 子目录以便在测试时重新创建它:

# hadoop-0.20 fs -rmr output

Deleted hdfs://localhost/user/root/output

接下来,请求用于执行 grep 的 MapReduce 作业。在这种情况下,并行执行 grep(映射),然后组合 grep 的结果(缩减)。清单 9 给出这个使用模型的 输出(为了简短,这里删除了一些输出)。注意,这里的命令请求是一个 grep ,它从 input 子目录获取输入,把结果放在 output 子目录中。最后一个参数 是要搜索的字符串(在这里是 'kernel')。

清单 9. 执行单词搜索计数的 MapReduce 作业 (grep)

# hadoop-0.20 jar /usr/lib/hadoop/hadoop-0.20.2+228- examples.jar

grep input output 'kernel'

10/04/30 09:22:29 INFO mapred.FileInputFormat: Total input paths to process : 2

10/04/30 09:22:30 INFO mapred.JobClient: Running job: job_201004291628_0010

10/04/30 09:22:31 INFO mapred.JobClient: map 0% reduce 0%

10/04/30 09:22:42 INFO mapred.JobClient: map 66% reduce 0%

10/04/30 09:22:45 INFO mapred.JobClient: map 100% reduce 0%

10/04/30 09:22:54 INFO mapred.JobClient: map 100% reduce 100%

10/04/30 09:22:56 INFO mapred.JobClient: Job complete: job_201004291628_0010

10/04/30 09:22:56 INFO mapred.JobClient: Counters: 18

10/04/30 09:22:56 INFO mapred.JobClient: Job Counters

10/04/30 09:22:56 INFO mapred.JobClient: Launched reduce tasks=1

10/04/30 09:22:56 INFO mapred.JobClient: Launched map tasks=3

10/04/30 09:22:56 INFO mapred.JobClient: Data-local map tasks=3

10/04/30 09:22:56 INFO mapred.JobClient: FileSystemCounters

10/04/30 09:22:56 INFO mapred.JobClient: FILE_BYTES_READ=57

10/04/30 09:22:56 INFO mapred.JobClient: HDFS_BYTES_READ=113144

10/04/30 09:22:56 INFO mapred.JobClient: FILE_BYTES_WRITTEN=222

10/04/30 09:22:56 INFO mapred.JobClient: HDFS_BYTES_WRITTEN=109

...

10/04/30 09:23:14 INFO mapred.JobClient: Map output bytes=15

10/04/30 09:23:14 INFO mapred.JobClient: Map input bytes=23

10/04/30 09:23:14 INFO mapred.JobClient: Combine input records=0

10/04/30 09:23:14 INFO mapred.JobClient: Map output records=1

10/04/30 09:23:14 INFO mapred.JobClient: Reduce input records=1

#

作业完成之后,检查 output 目录,找到结果文件,然后通过执行文件系统 cat 操作查看其内容(见清单 10)。

清单 10. 检查 MapReduce 作业 的输出

# hadoop-0.20 fs -ls output

Found 2 items

drwxr-xr-x - root supergroup 0 2010-04-30 09:22 /user/root/output/_logs

-rw-r--r-- 1 root supergroup 10 2010-04-30 09:23 /user/root/output/part-00000

# hadoop-0.20 fs -cat output/part-00000

17 kernel

#

基于 Web 的界面

您已经知道如何检查 HDFS 了,但是如 果要寻找 Hadoop 的操作的相关信息,会发现 Web 界面很有用。位于 Hadoop 集群最上层的是 namenode,它管理 HDFS。可以通过 localhost:50070 查看文件系统的高层信息(比如可用空间、已用空间和可用的 datanode)以及 正在运行的作业。可以通过 localhost:50030 深入检查 jobtracker( 作业状态)。注意,在这两种情况下都引用 localhost,因为所有守护进程都在 同一个主机上运行。

更进一步

本文讨论了一个简单的(伪分布 式)Hadoop 集群的安装和初始配置。在这里,我选用 Cloudera 的 Hadoop 发 行版是因为它简化了 Hadoop 的安装和初始配置。可以在 apache.org 找到许多 Hadoop 发行版(包括源代码)。

但是,如果缺少硬件资源,无法扩展 Hadoop 集群以满足自己的需要,那么 应该怎么办?由于 Hadoop 非常流行,可以很方便地在云计算基础设施中使用预 构建的 Hadoop VM 和租用的服务器运行它。Amazon 在 Amazon Elastic Compute Cloud (Amazon EC2) 中提供 Amazon Machine Image (AMI) 和计算资 源。另外,Microsoft 最近宣布将在它的 Windows® Azure Services Platform. 中支持 Hadoop。

通过本文很容易看出 Hadoop 显著简化了处理大型数据集的分布式计算 。本系列中的下一篇文章通过更多示例讨论如何在多节点集群中配置 Hadoop。

篇2:sed 实例,第 1 部分Unix系统

sed 实例,第 1 部分

通用线程 -- sed 实例,第 1 部分

自:IBM developerWorks 中国网站

原文转自:www.ltesting.net

篇3:如何实现iOS图书动画:第1部分(上)

原文链接 : How to Create an iOS Book Open Animation: Part 1 原文作者 : Vincent Ngo 译文出自 : 开发技术前线 www.devtf.cn 译者 : kmyhy

本教程分为2个部分,教你开发一个漂亮的iOS图书打开和翻页动画,就像你在Paper 53中所见到的一样:

在第1部分,你将学习到如何定制化Collection View Layout,并通过使用深度和阴影使App看起来更真实,

在第2部分,你将学习如何以一种合理的方法在两个不同的控制器之间创建自定义的过渡特效,以及利用手势在两个视图间创建自然的、直观的过渡效果。

本教程适用于中级-高级的开发者;你将使用自定义过渡动画和自定义Collection View Layout。如果你从来没有用过Colleciton View,请先参考其他iOS教程。

注意:感谢Attila Hegdüs创建了本教程中的示例项目。

篇4:如何实现iOS图书动画:第1部分(上)

从此处下载本教程的开始项目;解开zip压缩包,用Xcode打开Paper.xcodeproj。

编译项目,在模拟器中运行App;你将看到如下画面:

这个App的功能已经很完善了,你可以在你的书库中滚动,查看图书,选中某本图书进行浏览。但当你读一本书的时候,为什么它的书页都是并排放置的?通过一些UICollectionView的知识,你可以让这些书页看起来更好一些!

篇5:如何实现iOS图书动画:第1部分(上)

Here’s a quick rundown of the most important bits of the starter project:

关于这个开始项目,有几个重要的地方需要解释:

Data Models文件夹包含3个文件:

Books.plist 中包含了几本用于演示的图书信息。每本图书包含一张封面图片,以及一个表示每一页的内容的图片的数组。 BookStore.swift实现了单例,在整个App声明周期中只能创建一次对象。BookStore的职责是从Books.plist中加载数据并创建Book类实例。 Book.swift用于存放图书相关信息的类,比如图书的封面,每一页的图片,以及页号。

Books文件夹包含了两个文件:

BooksViewController.swift是一个UICollectionViewController子类。负责以水平方式显式图书列表。 BookCoverCell.swift负责显示图书的封面,这个类被BooksViewController类所引用。

在Book文件夹中则包括:

BookViewController.swift也是UICollectionViewController的子类。当用户在BooksViewController中选定的一本书后,它负责显示图书中的书页。 BookPageCell.swift被BookViewController用于显示图书中的书页。

在最后一个文件夹Helper中包含了:

UIImage+Helpers.swift是UIImage的扩展。该扩展包含了两个实用方法,一个用于让图片呈圆角显示,一个用于将图片缩放到指定大小。

这就是整个开始项目的大致介绍——接下来该是我们写点代码的时候了!

篇6:如何实现iOS图书动画:第1部分(上)

targetContentOffsetForProposedContentOffset(_:withScrollingVelocity:)方法用于计算每本书应该在对齐到哪个位置,它返回一个偏移位置,可用于设置Collection View的contentOffset。如果你不覆盖这个方法,它会返回一个默认的值。

在shouldInvalidateLayoutForBoundsChange(_:)方法后添加如下代码:

override func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint { // Snap cells to centre //1 var newOffset = CGPoint //2 var layout = collectionView!.collectionViewLayout as! UICollectionViewFlowLayout //3 var width = layout.itemSize.width + layout.minimumLineSpacing //4 var ffset = proposedContentOffset.x + collectionView!.contentInset.left //5 if velocity.x > 0 { //ceil returns next biggest number ffset = width * ceil(offset / width) } else if velocity.x == 0 { //6 //rounds the argument ffset = width * round(offset / width) } else if velocity.x < 0 { //7 //removes decimal part of argument ffset = width * floor(offset / width) } //8 newOffset.x = offset - collectionView!.contentInset.left newOffset.y = proposedContentOffset.y //y will always be the same... return newOffset}

这段代码计算当用户手指离开屏幕时,封面应该位于哪个偏移位置:

声明一个CGPoint。 获得Collection View的当前布局。 获得单元格的总宽度。 计算相对于屏幕中央的currentOffset。 如果velocity.x>0,表明用户向右滚动,用offset除以width,得到书的索引,并滚动到相应的位置。 如果velocity.x=0,表明用户是无意识的滚动,原来的选择不会发生改变。 如果velocity.x<0,表明用户向左滚动。 修改newOffset.x,然后返回newOffset。这样就保证书本总是对齐到屏幕的中央。

编译运行程序;再次滚动封面,你会注意到滚动动作将变得更整齐了。

要完成这个布局,我们还需要使用一种机制,以限制用户只能点击位于中央的封面。目前,不管哪个位置的封面都是可点击的。

打开BooksViewController.swift,在注释”//MARK:Helpers”下面加入以下代码:

func selectedCell() -> BookCoverCell? { if let indexPath = collectionView?.indexPathForItemAtPoint(CGPointMake(collectionView!.contentOffset.x + collectionView!.bounds.width / 2, collectionView!.bounds.height / 2)) { if let cell = collectionView?.cellForItemAtIndexPath(indexPath) as? BookCoverCell {return cell } } return nil}

selectedCell()方法返回位于中央的那个单元格。

替换openBook(_:)方法的代码如下:

func openBook() { let vc = storyboard?.instantiateViewControllerWithIdentifier(BookViewController) as! BookViewController vc.book = selectedCell()?.book // UICollectionView loads it's cells on a background thread, so make sure it's loaded before passing it to the animation handler dispatch_async(dispatch_get_main_queue(), { () -> Void in self.navigationController?.pushViewController(vc, animated: true) return })}

这里,直接调用新的selectedCell方法,并用它的book属性代替原来的book参数。

然后,将collectionView(_:didSelectItemAtIndexPath:)方法替换为:

override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) { openBook()}

这里,我们简单地删除了原来的打开某个索引处的图书的代码,而直接打开了当前位于屏幕中央的图书。

编译运行程序,我们将看到每次打开的图书总是位于屏幕中央的那本。

篇7:如何实现iOS图书动画:第1部分(上)

首先我们需要在BooksViewController中覆盖Collection View的默认布局方式。但当前的布局是在屏幕上显示3张图书封面的大图。为了美观,我们将这些图片缩减到一定大小,如下图所示:

当我们滑动图片,移动到屏幕中心的图片将被放大,以表示该图书为选中状态。如果继续滑动,该图书的封面又会缩小到一边,表示我们放弃选择该图书。

在AppBooks文件夹下新建一个文件夹组:Layout。在Layout上点击右键,选择New File…,然后选择iOSSourceCocoa Touch Class模板,并点击Next。类名命名为BooksLayout,继承UICollectionViewFlowLayout类,语言设置为Swift。

然后需要告诉BooksViewController中的Collection View,适用我们新建的BooksLayout。

打开Main.storyboard,展开BooksViewController对象,然后选择Collection View。在属性面板中,设置Layout 属性为 Custom,设置Class属性为BooksLayout,如下图所示:

打开BooksLayout.swift,在BooksLayout类声明之上加入以下代码:

private let PageWidth: CGFloat = 362private let PageHeight: CGFloat = 568

这个两个常量将用于设置单元格的的大小。

现在,在类定义内部定义如下初始化方法:

required init(coder aDecoder: NSCoder) { super.init(coder: aDecoder) scrollDirection = UICollectionViewScrollDirection.Horizontal //1 itemSize = CGSizeMake(PageWidth, PageHeight) //2 minimumInteritemSpacing = 10 //3}

上述代码作用如下:

设置Collectioin View的滚动方向为水平方向。 设置单元格的大小为PageWidth和PageHeight,即362x568。 设置两个单元格间距10。

然后,在init(coder:)方法中加入代码:

override func prepareLayout() { super.prepareLayout() //The rate at which we scroll the collection view. //1 collectionView?.decelerationRate = UIScrollViewDecelerationRateFast //2 collectionView?.contentInset = UIEdgeInsets( top: 0, left: collectionView!.bounds.width / 2 - PageWidth / 2, bottom: 0, right: collectionView!.bounds.width / 2 - PageWidth / 2 )}

prepareLayout()方法允许我们在每个单元格的布局信息生效之前可以进行一些计算。

对应注释中的编号,以上代码分别说明如下:

设置当用户手指离开后,Collection

View停止滚动的速度。默认的设置为UIScrollViewDecelerationRateFast,这是一个较快的速度。你可以尝试着设置为Normal 和 Fast,看看二者之间有什么区别。 设置Collection View的contentInset,以使第一本书的封面位于Collection View的中心。

现在我们需要处理每一个单元格的布局信息。

在prepareLayout()方法下面,加入以下代码:

override func layoutAttributesForElementsInRect(rect: CGRect) -> [AnyObject]? { //1 var array = super.layoutAttributesForElementsInRect(rect) as! [UICollectionViewLayoutAttributes] //2 for attributes in array { //3 var frame. = attributes.frame. //4 var distance = abs(collectionView!.contentOffset.x + collectionView!.contentInset.left - frame.origin.x) //5 var scale = 0.7 * min(max(1 - distance / (collectionView!.bounds.width), 0.75), 1) //6 attributes.transform. = CGAffineTransformMakeScale(scale, scale) } return array}

layoutAttributesForElementsInRect(_:) 方法返回一个UICollectionViewLayoutAttributes对象数组,其中包含了每一个单元格的布局属性,

电脑资料

以上代码稍作说明如下:

调用父类的layoutAttributesForElementsInRect方法,已获得默认的单元格布局属性。 遍历数组中的每个单元格布局属性。 从单元格布局属性中读取frame。 计算两本书的封面之间的间距——即两个单元格之间的间距——以及屏幕的中心点。 以0.75~1之间的比率缩放封面,具体的比率取决于前面计算出来的间距。然后为了美观,将所有的封面都缩放70%。 最后,应用仿射变换。

接下来,在layoutAttributesForElementsInRect(_:)方法后增加如下代码:

override func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool { return true}

返回true表示每当Collection View的bounds发生改变时都强制重新计算布局属性。Collection View在滚动时会改变它的bounds,因此我们需要重新计算单元格的布局属性。

编译运行程序,我们将看到位于中央的封面明显比其他封面要大上一圈:

拖动Colleciton View,查看每本书放大、缩小。但仍然有一点稍显不足,为什么不让书本能够卡到固定的位置呢?

接下来我们介绍的这个方法就是干这个的。

用饱经风霜进行造句

用成语四分五裂进行造句

用贻笑大方来进行造句

机械制图教程第1讲――绪论

《At-the-zoo》 第1课时教学设计

三国演义第1回合的读后感

西游记第1至14回读后感

技能和经验 第一部分(1~5问)

初中英语作文:用进行时态描写图画

教学设计1:乌鸦喝水第1课时

用Hadoop进行分布式数据处理,第1部分 入门(精选7篇)

欢迎下载DOC格式的用Hadoop进行分布式数据处理,第1部分 入门,但愿能给您带来参考作用!
推荐度: 推荐 推荐 推荐 推荐 推荐
点击下载文档 文档为doc格式
点击下载本文文档