《第一行代码——Android》封面诞生记

《第一行代码——Android》已经上市快一个月了,目前销售情况还算良好,也是特别感谢众多朋友的支持。其实一本书如果想要卖的好,除了内容必须要给力之外,封面的设计也是至关重要的,而本书的封面无疑是在充实的内容之外又披上了一层华丽的外衣。作为作者,其实我的任务就是将内容写好而已,其它所有相关工作都不是由我负责的。本书封面设计的所有细节都是由陈冰老师一手抓起的,之后他在图灵社区上记录了本书封面的诞生过程。在经过他同意的情况下,我将这篇文章转到我的博客上,也是让感兴趣的朋友们了解一些不为人知的小故事。


以下所有的第一人称 “我” 都指的是 “陈冰” 。


每一本好书的封面的诞生都不是轻松的事情。不仅不是轻松的事情,事实上正相反,几乎无一例外都是艰难的过程。但如果最终得偿所愿,一本书找到了它的封面,那这个艰难的过程就会有一个愉快的结果。


什么叫一本书找到了它的封面?就是当你拿到这个封面时,你大脑中有一个强烈的意识,不会有任何一个其他封面更适合这本书了。


这本书,我最初给它这个书名时,我就意识到这是个好书名,但对于给这个书名设计一个好封面而言,却是个极难的课题。“第一行代码”是我策划的一个给编程初学者看的系列,本书是这个系列的第一本书。


在策划这本书(这个系列)时,我就想好要有一个独一无二的形式上的突破,要给读者以新意和独特的阅读体验。为此,我决定给它引入一个经验值、升级与宝物系统,这是在此前的任何计算机图书(据我所知也包括其他所有类别的图书上)上都没有过的事情。


基于这些考虑,这本书的封面必须同时满足以下四个特点:
一, 应该庄重、可信、能让读者感到有一股内在的力量,让读者感到这本书所讲述的知识是可信赖的。
二, 有一种神秘感、带有一些魔幻现实主义的色彩,让读者感到这本书与其它书明显不同;
三, 让初学者有亲切感,IT感也必须在其中体现,让读者感到这一场景他非常熟悉,有认同感。
四, 要有绝对的视觉冲击力,在网店上销书,都是邮票大小的展示区,不可能让你捧到手里仔细端详,如果封面不能在邮票大小的面积上给你造成视觉吸引力,但这个封面无论设计得多么绝妙都是失败的。 设计一个封面不难,但要设计一个好看的封面就相当不易,而要设计一个既好看又能卖的封面则是极难的事情。


为了达到这个效果,我开始构思这个封面。在“第一行代码”这几个字的字体上做文章的念头曾在我脑海中一闪而过,但立马就被我否定了,那样出来的效果会过于张扬,同时又不免落入俗套,而且弄不好就会搞得像本财经类图书。


我告诉自己,既然是本给初学者看的书,那首先就要让初学者有亲切感,要设计一个典型的元素,让初学者一看到它亲切感和熟悉感就立马油然而生。八年前,我在清华时曾策划过一个“第一步”系列,当时我设计的封面元素就是在画面中央有一个“Hello,World”字样,很醒目。




Hello,World对于初学者而言无疑是最熟悉的元素,但我不喜欢重复自己,对于这个“第一行代码”系列,我要重新琢磨一个元素。我想到了我当年刚刚学习编程时,在深夜灯下电脑前工作的情景,也想起来以前深夜写计算机书时的情景,不管是写代码,还是写计算机书,深夜电脑前工作的情形是每个程序员,无论新手还是老手都非常熟悉有亲切感的画面,甚至此时此刻的你就是这样。所以我决定就用这个画面这个场景来做这个封面关键识别元素。


那么这个识别元素具体要有哪些物件组成呢?我开始进一步构思这个场景具体要包含哪些元素。我凭着直觉,让脑海中自发产生的图像带我前行,我看到一个小程序员坐在书桌前,他背对着我,面前是一台ThinkPad笔记本电脑,左手侧有一台iPad,右手侧有一台三星Note大屏手机,还有一碗刚泡好正待吃的方便面,一杯果汁,一摞书,因为正在从事Android开发,所以书上还有一个Android小机器人的手办,还有一盆绿植(我又在脑海中仔细看了看,原来是盆仙人掌)。我把这些元素在纸上画出来。为了让画面更丰富,我瞅了瞅我自己的书桌,然后又在画面中加了一个水杯,几张纸和一支笔。为了让画面更生动和富有趣味,我在桌旁的地面上加了一只小猫,它正好奇的望向桌底某个方向,似乎发现了什么异次元的东西。


这是当时我画的草图:




当时我在主画面周围还画了一些家具、一个窗户,以及窗前的天文望远镜(望远镜的出现有两种含义,这是这个小程序员的爱好,同时也意味着梦想),后来我意识到,整个画面很像我房间的样子。


我让与我合作多年的插画师巫俊武来画这个插画。这是插画的第一个版本:




不萌,而且过于写实,欠缺一些魔幻感,于是继续修改,得到下面这个版本:




有点萌了,有点味道了。于是,我让俊武先进行一下着色,看看效果。我当时给了俊武一幅插画效果(这是《梦想还是要有的,万一实现了呢》一书中的一幅插画),让他就按照这幅插画的效果来进行着色。因为我当时希望这本书的画面要温暖、明亮、色彩丰富,看着让人心生喜悦,带给人阳光向上的感觉,同时时间是晚上,所以这幅插画非常符合我要求。




结果,俊武一番神勇发挥后,得到下面这个让我大跌眼镜的效果:




当时又进行了一些着色的调整,但始终离我要的效果相去甚远(俊武不太擅长我要的那种着色风格),于是我果断放弃着色,决定就用黑白色来实现这幅插画。


我开始思考怎样才能让黑白的插画产生足够的力度,那就必须有足够的细节,同时笔触要加粗,粗笔触本身就会带来细节感和质感。笔触太细,必然会有单薄感、缺乏力度。因为缺少细节而导致缺少力度,所以我给插画师找了一些素描风格的插画,让他往那种效果上靠拢,几经修改,得到下面这个版本。




画面开始有一些厚重感和力量感了,但人物的脑袋有问题,不够大不够圆,继续修改。几经修改,得到满意的版本(我当时以为的最终版本)。




然后,我又让俊武照着我的另一副草图画好了封底用的插画。




这个封底的插画是和封面插画相呼应的,封面插画是在家里(屋内)看到的情景,而封底插画是同一时间在屋外(小区里)看到的这家的情景,整栋楼的灯光都熄灭了,所有人都入睡了,只有这个小程序员的房间还亮着灯,正在认真地努力地写着代码。他的梦想是成为优秀的程序员。


因此,我在封底写下了这样一句宣传语:
我挥舞着键盘和本子,
发誓要把世界写个明明白白。
两行字下面的那个小灰块代表正在闪烁的光标。


然后,我把全套封面设计资料(包括插画、封面宣传语、目录、样章等等)交给我的设计师绿豆(真名潘建永),并电话中跟他沟通了这个封面的设计要求。一周后,我拿到了下面的版本,我在已经坐在椅子里的状态下又进一步跌坐在了椅子里。




简直乱成一锅渣了,而且画面很单调,毫无让人去翻阅的念头。绿豆跟我说,他感到这幅黑白的插画限制了他的设计发挥,因为为了配合一幅黑白的画,封面的底色几乎只能是黑白的(至少我和他当时异脑同思都是这么认为的)。于是,事情几乎又回到了起点,还是必须搞出一幅着色的插画才行,才好后续设计的发挥。我安慰了一下绿豆受伤的心,决定继续去寻找合适的插画师。我在chuangyiren.cn网站上翻阅了几百页,找到了多位优秀的插画师,然后我从中选了一位插画师,和他电话沟通后,请他开始画这幅插画。


我这时对这幅插画的画风应该是怎样的,已经有了一些想法上的变化,我感到如果画面和上面提到的《梦想》那本书的画风一样的话,会显得过于卡通,有些低幼,而且缺少神秘感,与这本书中所包含的这套令人耳目一新、匪夷所思的升级与宝物系统的感觉不是很搭,同时,这种画面缺乏厚重感和力度,由于颜色过多,在网店小图上展示时也很难形成视觉冲击力。因此,我决定放弃这种画风,转而寻求一种能满足神秘、厚重、且具有强力的视觉冲击力的画风。


这时,我突然想到了我以前看过的一部动画片电影《凯尔经的秘密》。这部动画片的风格正适合这本书。




但最终拿到的插画效果和我想要的仍相去较大。




我这时感觉多少有点崩溃,我觉得我最初制定的设计方案或许很不错,但实现难度较大,而且即使完全按照我的设想实现了,画面冲击力很可能仍然不够大。


在寻找新的插画师,以及让新的插画师试画的期间,我也同时在让俊武把原来的素描版插画进行完善,因为此时我猛然想到,我不能仅仅只在封面上写上一句“第一本引入经验值、升级与宝物系统的计算机书!”就想当然的认为读者会信了,并且会感受到这句话意味着什么。我必须要在封面上直接就以画面的形式把这本书所加入的这套独一无二的经验值和升级系统体现出来,所以只画出小程序员显然是不够的,还要有这套系统中所营造的那个Android神界的人物、角色、物品。


所以,我让俊武在画面上增添了这样七个元素:


一, Android前辈遗失的修行卡
二, 外围守护者
三, 信心增强大力丸
四, 上古奇书
五, 神树
六, 粗布Android战袍
七, 界面砖家(法师造型)


我画了草图,并跟俊武说明了这些元素各自的形象。


第二天,我得到了一个身材矮小的牛魔王(俊武想象中的外围守护者),以及忘记从哪个软件里跑出来的Wizard(俊武想象出的巫师)。




我平静了一下心情,调整好思路,继续与俊武沟通。我从网上找到了这七个元素中每一个我满意的造型,然后让俊武参考它们进行绘画,果然,这次的接近了不少。




但守护者的神态不够威武,而且身高不够,感觉不到是神界的人物,更像是个脾气和善的在自由市场卖猪肉的胖商贩,巫师的身高也不够,感觉像西游记里的土地或是小矮人之类的角色。我让俊武想象希腊、埃及那些神庙中的顶天立地的神像,感受他们的体积和庞大,体会他们的威严,经过数次修改后,我拿到了满意的版本。




插画很完美了,但封面的总体设计方案的问题依然没有解决。我集中精力只想一个问题,怎样让画面有视觉冲击力,显然必须保持单色色块尽可能的大,因为一旦画面被多种颜色和色块分散后,在网店上邮票大小的面积上就更形不成什么视觉面积了,所以我想到必须采用整个封面用单一色调的方案,可选的颜色有红色、黄色、金色、蓝色、绿色,充分琢磨和体会后,我选了红色,蓝色也很有冲击力,但不管是读过本书内容还是这套升级系统,你都不会在脑海中产生蓝色这个颜色。你的脑海中会产生绿色这个颜色,但绿色在网页上的视觉冲击力太弱,在催人向上的力度上也较差。红色最合适,但不能是大红,大红太刺眼,而且略显俗气,所以我用了暗一些的红色,绿豆说他是往红色中加了20的黑,出来的这个效果非常棒。


为了尽量让红色占有更大的视觉面积,我想了一个方案,在画面前景色中只保留小程序员和那只小猫是白色的,而把其他元素(守护者、神树、古书、巫师等)都放入背景的红色中,作为底纹呈现出来,这样就不会喧宾夺主,而且有一种那些神界的人物是这个小程序员的脑海中的想象或者说回忆的韵味。此外,单独的红色,即使加上这些神界的元素做底纹还是略显缺乏一点层次,我又让绿豆在底纹中加入了一些植物的叶子。我选了恐龙时代就存在的蕨类植物的叶子,因为这些叶子有一种与生俱来的神秘感和沧桑感,若隐若现间,烘托出本书应有的神秘和庄重的味道。




此前,由于封面上宣传语太多,不方便设计,所以我让绿豆把其中一部分宣传语设计到了腰封上。腰封对这些重要的宣传语能起到更好的宣传作用,同时封面本身也干净了很多。


至此,整个封面设计完成。




完整的展开封面:




关注我的技术公众号,每天都有优质技术文章推送。关注我的娱乐公众号,工作、学习累了的时候放松一下自己。

微信扫一扫下方二维码即可关注:

        

  • 84
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 64
    评论
Broadcast 广播是 Android 系统中的一种重要的组件通信方式,它可以让应用程序之间进行消息传递,从而实现应用程序之间的数据交换和功能协同。广播可以被用来处理一些系统事件或应用程序内部的特定事件。在本篇文章中,我们将学习如何在 Android 应用程序中使用广播。 一、广播的基本概念 广播是指一种可以跨应用程序发送和接收消息的机制,它允许应用程序向全局范围内的其他应用程序通知某些事件的发生。Android 中的广播可以分为两类: 1.标准广播(Normal Broadcast):这种广播是完全异步的,所有的接收者都会在同一时刻接收到广播消息,因此它们之间没有任何优先级的区别。使用标准广播时,所有接收者都无法终止广播的传播,这也是标准广播的一个缺点。 2.有序广播(Ordered Broadcast):这种广播是同步执行的,所有的接收者都是按照优先级顺序依次接收广播消息的。在广播传递过程中,每个接收者都可以截断广播的传播,使得后面的接收者无法收到广播消息。如果某个接收者截断了广播的传播,那么其后面的接收者就无法收到广播消息。这种广播的优先级由高到低依次为:1000、500、0、-500、-1000。 二、发送和接收广播 1.发送广播 在 Android 应用程序中,我们可以通过以下代码来发送广播: ```java Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST"); sendBroadcast(intent); ``` 上述代码中,我们首先创建了一个 Intent 对象,然后将其 action 设置为 "com.example.broadcasttest.MY_BROADCAST",这个 action 可以自己定义。最后,我们调用了 sendBroadcast() 方法来发送广播。 2.接收广播 要接收广播,需要在代码中注册一个 BroadcastReceiver 对象,并在其 onReceive() 方法中处理广播消息。以下是一个简单的例子: ```java public class MyBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Toast.makeText(context, "Received in MyBroadcastReceiver", Toast.LENGTH_SHORT).show(); } } ``` 在上述代码中,我们创建了一个 MyBroadcastReceiver 类,并实现了其 onReceive() 方法。当收到广播消息时,系统会自动调用该方法,并将广播消息以 Intent 对象的形式传递给该方法。在 onReceive() 方法中,我们可以根据 Intent 对象中携带的信息来进行相应的处理,例如弹出一个 Toast 提示框。 3.注册广播接收器 在 Android 应用程序中,我们需要使用 IntentFilter 对象来指定要接收的广播类型。以下是一个注册广播接收器的例子: ```java MyBroadcastReceiver receiver = new MyBroadcastReceiver(); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction("com.example.broadcasttest.MY_BROADCAST"); registerReceiver(receiver, intentFilter); ``` 在上述代码中,我们首先创建了一个 MyBroadcastReceiver 对象,然后创建了一个 IntentFilter 对象,并将要接收的广播类型设置为 "com.example.broadcasttest.MY_BROADCAST"。最后,我们调用 registerReceiver() 方法来注册广播接收器。 4.注销广播接收器 当我们不再需要接收某个广播时,应该及时将其注册的广播接收器进行注销。以下是一个注销广播接收器的例子: ```java unregisterReceiver(receiver); ``` 在上述代码中,我们调用 unregisterReceiver() 方法来注销广播接收器。 三、有序广播的使用 有序广播可以让我们按照优先级顺序接收广播消息,并且可以截断广播的传播。以下是一个有序广播的例子: ```java Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST"); sendOrderedBroadcast(intent, null); ``` 在上述代码中,我们调用了 sendOrderedBroadcast() 方法来发送有序广播。由于没有指定接收者的权限,因此我们将其设置为 null。 接下来,我们需要在代码中注册一个 BroadcastReceiver 对象,并在其 onReceive() 方法中处理广播消息。以下是一个简单的例子: ```java public class MyBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String msg = getResultData(); Toast.makeText(context, msg + " Received in MyBroadcastReceiver", Toast.LENGTH_SHORT).show(); setResultData("Hello MainActivity"); } } ``` 在上述代码中,我们首先调用 getResultData() 方法来获取上一个接收者设置的数据,然后弹出一个 Toast 提示框,并将自己的数据设置为 "Hello MainActivity"。 接下来,我们需要指定广播接收者的优先级。在 AndroidManifest.xml 文件中,我们可以使用 priority 属性来设置广播接收者的优先级。以下是一个简单的例子: ```xml <receiver android:name=".MyBroadcastReceiver"> <intent-filter> <action android:name="com.example.broadcasttest.MY_BROADCAST"/> </intent-filter> <priority android:priority="1000" /> </receiver> ``` 在上述代码中,我们将 MyBroadcastReceiver 类注册为广播接收者,并将其优先级设置为 1000。 为了演示有序广播的效果,我们可以再注册一个 BroadcastReceiver 对象,并将其优先级设置为 500。以下是一个简单的例子: ```java public class AnotherBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String msg = getResultData(); Toast.makeText(context, msg + " Received in AnotherBroadcastReceiver", Toast.LENGTH_SHORT).show(); setResultData("Hello MainActivity"); } } ``` 在上述代码中,我们将 AnotherBroadcastReceiver 类注册为广播接收者,并将其优先级设置为 500。 最后,我们在 AndroidManifest.xml 文件中注册这两个广播接收者,代码如下: ```xml <receiver android:name=".MyBroadcastReceiver"> <intent-filter> <action android:name="com.example.broadcasttest.MY_BROADCAST"/> </intent-filter> <priority android:priority="1000" /> </receiver> <receiver android:name=".AnotherBroadcastReceiver"> <intent-filter> <action android:name="com.example.broadcasttest.MY_BROADCAST"/> </intent-filter> <priority android:priority="500" /> </receiver> ``` 在上述代码中,我们将 MyBroadcastReceiver 和 AnotherBroadcastReceiver 类都注册为广播接收者,并指定了它们的优先级。 在执行上述代码后,我们可以看到,在发送广播时,首先会将广播消息发送给优先级为 1000 的 MyBroadcastReceiver 类,然后再发送给优先级为 500 的 AnotherBroadcastReceiver 类。在 MyBroadcastReceiver 类的 onReceive() 方法中,我们可以获取到 AnotherBroadcastReceiver 类设置的数据,然后弹出一个 Toast 提示框,并将自己的数据设置为 "Hello MainActivity"。最后,我们可以看到,弹出的 Toast 提示框中显示的内容为 "Hello MainActivity Received in MyBroadcastReceiver",这表明 MyBroadcastReceiver 类成功地截断了广播的传播。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 64
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值