如何给Launcher3添加左屏

(系列文章点这里)

如果你用过谷歌即时桌面(Google Now)的话,你一定知道滑到桌面最左屏会是一个搜索界面,而且会呈现一些卡片比如天气,行程,新闻等等。这个东西也是我们可以自定义的,谷歌即时桌面其实也是基于Launcher3的。想必AOSP中一定有源码可以控制最左屏。

2014-10-23_14-14-48

 

如果你已经导入了Eclipse项目,可以到Launcher类中寻找Launcher.hasCustomContentToLeft()方法,从字面上理解就是左边是否有自定义内容。之后跟自定义内容相关的方法或者变量的名字基本都跟“custom content”相关。这个方法默认是返回false的,也就是最左屏不存在。不妨替换成true试试,运行后我们可以发现的确可以滑到左屏的,但是什么东西都没有,只留一个搜索框。

下一步是向自定义内容中添加View了,添加的方法是Workspace.addToCustomContentPage(…),你可以传递一个View和与左屏相关的回调接口。然后就OK了。你可以在需要的时候调用这个方法,什么时候调呢?Google已经帮你想好了。就是Launcher.addCustomContentToLeft()方法,这个方法会在Launcher.onFinishBindingItems()中调用到,也就是桌面加载结束的时候加载自定义内容。着实帮你省去了很多开发时间。

所以说,如果你想要在左屏添加天气呀,系统设置呀等是完全OK的,毕竟传递个View进去就行,你也可以弄个Fragment专门控制左屏的内容和逻辑。这样的设计还是挺符合用户的需求的,毕竟Google的东西我们在大陆没办法正常使用,你如果能设计一个类似的,国内用户可以正常使用的包含左屏信息页的Launcher,我觉得还是挺有价值的。

再说说技术实现吧,既然是在Workspace上添加一个View,那么他应该是放在CellLayout里面的,但是为什么他和其他的CellLayout大小不一,而且占据全屏呢。我们找到桌面加载每一屏的代码,在Launcher.bindScreens()里面,会在加载完正常的图标屏之后再加载自定义的左屏,通过Workspace.createCustomContentPage()。然后会发现他给新生成的CellLayout的LayoutParams新添加了属性值,isFullScreenPage=true,一旦有了这个属性,在PagedView(Workspace的父类)的onMeasure和onLayout就会对其做特殊处理,保证其占据全屏。

 

继续阅读 →

Android图形 —— 从哪里开始?

你一定遇到过Android现有的UI控件无法满足项目需求的情况,一般来说你可能需要将多个UI组合起来,或者说需要自己控制一些触摸事件,又或者为了得到更好的图形效果等等。这个时候就需要自定义控件了。

自定义控件的一个重点就是实现就是去重写他的绘制过程,也就是View.onDraw(Canvas canvas)方法。这个里面就是绘制图形的过程了,比如说一个Button,绘制按钮和按钮上的文字都是在它自己的onDraw方法中完成的。如果你想给ImageView加个蒙版,可以继承ImageView并且重写他的onDraw方法,调用完父类的onDraw之后,再自己Canvas来画一个黑色的半透明矩形,这样就可以对现有的控件进行加工了。

Canvas是什么呢?是画布,你绘制东西的时候就是绘到了这个画布上,给用户显示的东西也是这个画布上的东西。通常来说,当你调用到onDraw方法的时候对应的View已经确定了他的宽度和高度(关于View的measure和layout过程以后再详述)。那么在Canvas上,你画的范围就只有View对应的大小了。我们用代码来描述下:
(更多…)

继续阅读 →

Android图形必知必会

最近接触了Android图形方面的知识,发现其中还是有很多比较深入的东西的。

我决定写一系列的文章来讲解android.graphics.*包种的各种类的用法,如果用这些东西来给我们的应用UI增添一些色彩。如果你熟练运用这些东西,不仅可以可以实现惊艳的效果,还可以增加界面的流畅度,减少内存使用等等。

android.graphics.* 包里面主要由以下一些类:

  • Canvas
  • Bitmap及其相关的类
  • Xfermode及其子类
  • Paint及其相关类和内部类
  • Shader及其子类
  • Rect,Color,Point,Path等基础类
  • 等等等

好了,坑先挖在这里。。后续文章点页面上方的“ANDROID”

 

继续阅读 →

Canvas.drawText绘制文字为什么会偏上?

如果你经常使用Canvas的draw***方法去绘制一些图像图形,你会知道绘制的时候坐标是从Canvas左上角开始计算的,如果想要把一个图像放到某个位置,直接drawBitmap传递图片左上角的坐标就行了。

那drawText就不一样了,如果你传递进去字符串,会发现文字的位置和你指定的不一样。

卧槽为啥。Android的文档也没有仔细说,打开源码一看,又跑到native代码里去执行了。经过我奋力地Google,终于把这个问题搞清楚了。

1408964085_thumb.jpeg

对于一段文字来说,如果你想把他画到Canvas上,首先你要确定这段文字的范围,即宽度和高度,那么怎么去取这一段的高度呢,如果你在网上搜,会有很多种答案,具体应该用哪一种呢?这要看你到底需要什么样的尺寸了。

Paint.getTextBounds: 当你通过这个方法来获取尺寸的时候,你可以得到能够包裹文字的最小矩形,就是图中红色边框的那部分,你可以得到一个Rect对象,包含这个最小尺寸的几个值。坑其实就在这里:这里的Rect对象坐标并不是以左上角为准的,而是相对于左边中间靠下位置的一个点,就是图中的黄色五角星。而这里水平的Baseline指的是字符串对齐的一条线(真正的含义可以需要更深入了解字体渲染的知识了)。既然这样,r.top就是一个负值了,r.bottom会是一个小一点的正值,r.left和r.right在图中画的都很清楚。通过r.width()和r.height()来获取尺寸。

那么文字的偏移就好说了,比如说你要把文字画在Canvas的左上角,坐标是(0,0),但是当你通过:

canvas.drawText(“dangwen”,0,0,paint);

来画文字的时候,发现只有文字的下半部分画出来了,因为你传递进去的参数应该是以Baseline为标准的,正确的方法是:

canvas.drawText(“dangwen”,-r.left,-r.top,paint);

Paint.getFontMetricsInt(): 当你通过这里方法来获取尺寸的时候,你获取的只是一个垂直方向上的尺寸,这里的ascent代表的是字体的上部,descent代表的是字体的下部,这里需要注意的是这和上面获得的Rect的top和bottom不太一样,他们比比ascent和descent距离稍微小一些,这些具体的高度可能和不同的字体和渲染方式有关系,这里就不深入了 #我是不懂#。

然后如果把文字写入TextView(图中蓝色部分)并且设置TextView的高度和宽度设为wrap_content,那么TextView的高度就正好是FontMetricsInt.top – FontMetricsInt.bottom, 那宽度呢? Paint.measureText()。

继续阅读 →

读书读不进去

话说我这里说的读书不是读技术相关的书籍,是文学类,小说类的文章。

前一段时间读了《陆犯焉识》,是在《归来》上映之前。刚开始读的时候很感兴趣,但是读着读着就耐不下性子了,总是感觉,我靠作者怎么这么啰嗦,这都快高潮了怎么又加了一个人物,我真的不care这个多出来的人物是干什么的。然后就耽搁了,现在kindle上进度还是显示33%,不想翻看。回想上大学之后,真的是没有读过很多文学类的文章了,并不是没有兴趣,而是很急躁,读了一会就想着怎么还没看完,好像在完任务一样。我一直在向为什么。

后来一想,我操,我一定是急着想写代码!

PS:本篇使用Blogo(Mac App Store首页这几天放的那个)发布,挺方便的推荐使用。

继续阅读 →

Android和iOS开发的一些异同

前一段时间用业余时间熟悉了下iOS开发,感受了下移动开发的另一面。

我同时参考了好几个资料,先看的是CodeSchool上iOS Path的Try Objective-CTry iOS,对于基本的语言和基本的在iOS上的应用熟悉了下,然后阅读《iOS开发指南:从零基础到App Store上架》来快速上手,这个过程中熟悉了Storyboard、常见的UI控件、表视图、导航设计和常用的设计模式。最后跟着@MengTodesign+code 完整地实现了一个客户端,学习了iOS的一些设计概念,CocoaPods以及开源库的使用,Sketch的使用等等。

对于一个陌生领域的开发者,接触到一个新的平台的时候,急需知道的是支撑一个应用的基本框架是什么,简单来说,就是应用的界面构成,UI和code的结合,事件处理,网络和常见问题的处理模式等等。就那我来说,我第一直觉就是想知道界面如何构成,因为这样是最直观并有成就感的,我当时的困惑是为什么 Try iOS 里面在代码里搞搞,界面就出来了,而书上的却一直使用拖拽,后来看到 “代码手写UI,xib和StoryBoard间的博弈,以及Interface Builder的一些小技巧”,才清楚了一些。再看看Android,情况好像好一些,因为基本上所有的教程都是从建立Activity并setContentView来描述界面的,不会有不清楚的地方,Android也可以用代码来控制UI,但是跟iOS一样不太好理解。

从开发环境来说,Xcode的使用体验已经非常良好了,UI很棒很简洁,该有的都有,自动补全让我很长时间不清楚Objective-C的函数到底是怎么构成的。。。不满的是在13寸rmbp上拖拽产生IBOutlet的时候屏幕空间明显不够用。同时也试用了AppCode,感觉一般。Android IDE是基于eclipse的,eclipse的界面实在是让人受不了,不过很成熟,遇到问题解决起来也快。我的个人项目已经切换到Android Studio了,界面上感觉良好,新的构建系统使得引用开源库十分方便,以后也会是方向。自动补全,重构,缩进,快速查找,配色,git支持等等两个开发环境都能满足日常需要,没有太多要吐槽的。

从布局组织上来说,Android使用的是xml,日常的界面都是在xml文件上进行更改,其中各种具体的属性可以精确控制各种组件,但是图形界面的预览功能还不是很成熟,问题多多,所以用的比较少。一般来说,一个Activity对应一个xml布局,布局中的对象可以指定一个id(类似于iOS的Identifier),在Activity的onCreate中通过findViewById()来获取布局中个个组件的对象。而iOS的界面组织可以通过一个Storyboard文件来完成,跟Android的Activity对应的概念是ViewController,在Storyboard可以拖一个ViewController出来形成一个界面,在上面添加UI组件,他可以有一个类继承ViewController作为这个界面的控制类,做一些响应UI事件的工作等等。

从开源库的使用来说,CocoaPods已经很不错了,Eclipse引用库类似,但是如果多个项目包含同名的库的话很麻烦。Android Studio很好地解决了这个问题。总体来说,开源库的引用方式也比较成熟了,而且各种库在github上也是数不胜数,庞大的开发者人群给我们贡献了很多优秀的项目,搞Android的点这里,搞iOS的点这里

从部署的角度来说,各有利弊。我目前还没有在App Store上发布过作品,不过对于苹果的审核有所耳闻,苹果对于品牌形象维护比较严格,可能存在的违规的都应尽量避免,很多开发者叫苦不迭,不过这也同时提高了App Store的应用质量。Google Play就相当于大杂烩,我的应用 Android Weekly 提交之后没隔几天就成功了,一般晚上更新,第二天早上就可以上线了。不过国内的应用市场真的是参差不齐,审核进度不一,提交内容不一,而且像豌豆荚还需要其他应用市场的详情页,真的是。。。

还有一些相同的地方,比如说列表控件,ListView对应UITableView,ListActivity对应UITableViewController,Adapter对应UITableViewDataSource,ListView.setOnItemClickListener对应UITableViewDelegate中的didSelectRowAtIndexPath。还有页面之间的跳转,Android上是用Context.startActivity(),而iOS是在两个ViewController之间连一条线(Segue),代表从一个页面调到另外一个页面的动作,在需要的时候(比如按钮按下)执行这条线就行了。

如果说,学会iOS需要100天,学会Android需要100天,那么把两者都学会则需要150天就OK了。很多移动设计的概念是相似的,触类旁通。当然,如果你要再深入的话,必须通过不断实现需求来提高,这种需求来源于日常工作,或者日常生活,比如说,用类应用不符合你的使用习惯,你需要做出一个更优秀的App来满足自己。

继续阅读 →

PagedView的原理 – 滑动

(系列文章点这里)

PagedView是用来左右滑屏的,Workspace正是他的子类,这里的Page就是桌面上一页一页的内容。其实他和ViewPager差不多,连名字都近似,不过PagedView更自由更复杂一些。

代码这么多,这得分析到啥时候去呀。

先说下这个滑动的过程吧。如果你还不熟悉android的触摸事件控制流程,点击这里。然后打开eclipse一步一步跟踪代码。
(更多…)

继续阅读 →

android常用的adb命令

(文章出处:http://www.growingwiththeweb.com/2014/01/handy-adb-commands-for-android.html)

 

查看所有已经连接上的设备:

这个命令可以查看所有已经连接上的设备和他的设备ID:

adb devices

如果有多个设备连接到电脑,可以通过 adb -s DEVICE_ID 来指定用哪一个。

 

安装应用:

通过install命令来安装apk文件,-r参数可以重新安装某个应用并保留应用数据。

adb install -r APK_FILE

#举例

adb install -r ~/application.apk

 

卸载应用:

adb uninstall PACKAGE_NAME

#举例

adb uninstall com.growingwiththeweb.example

(更多…)

继续阅读 →

Launcher3分析之拖动图标的流程——放下

(系列文章点这里)

我们来看下放下的过程,对应的触摸事件是ACTION_UP,我们直接跳到DragController的onTouchEvent。在处理ACTION_UP的时候多调用了一次handleMoveEvent,可能是因为ACTION_UP相对于上一次的时间也会有位置的变化。

up松手的时候会判断是是不是在“扔”图标(通过isFlingingToDelete),如果你用的不仔细的话,可能发现不了这个扔的过程:在说面拖动某个图标,然后快速甩向屏幕上方,就会触发删除的事件。这里检查你是否在扔是通过VelocityTracker来计算的,他会记录每次事件,然后计算出速度,包括X方向和Y方向的。如果不是在“扔”,就会调用放下图标最重要的一个方法,drop方法。
(更多…)

继续阅读 →

Launcher3分析之拖动图标的流程——移动

(系列文章点这里)

移动的逻辑还是比较清楚的,因为他抽象出来的模型十分易于理解的。

DropTarget是一个可放置(drop)区域的抽象,也就是我们松开手的时候想要把图标放到某个东西上,这个东西就是DropTarget,实现他的都是View,比如说文件夹,Workspace,删除区等等,你可以通过“ Open Type Hierarchy”来查看哪些类继承了DropTarget接口。下图是他比较重要的几个接口:

droptarget
(更多…)

继续阅读 →