这一周相对没有春节时这么闲了,白天也比较多的工作要做,每天晚上又要被我三岁的女儿折腾到十点, 实在没有多少时间学习。在前一周的基础上,这周我试着自己练习写了一个个人管理的android的程序,主要实现万年历,日程,随手便贴,短信群发等一些功能。下面总结一下自己在其过程中的一些心得和体会,都是一些没技术含量的活,我只写下自己的思路,不贴具体的代码了。苦于周围没有人可交流,大部分功能都是自己闭门造车或参考网上的资料实现,也不知道是否合理,望高手能加以指正。
页面布局是android开发比较重要的一部分,相对PC程序,由于手机的屏少,要想让用户有好的体验,UI设计就更为重要了。相对.net中的form,android的页面设计也更为复杂。最开始我是直接试着在layout中画了几个控件,位置和大小也是固定的,结果一到摸似器中,界面全乱了。后来才摸索出一些布局组件的用法。
这两个应该是最常用的两个布局组件了。LinearLayout一般用来把界面分成几部分,可以设置它的orientation,指定它是横向还是纵向的。RelativeLayout是一个相对布局的组件,非常好用的一个组件。它里面的控件都可以随意设定相对位置,可以是相对于相邻的控件(layout_toLeftOf等),也可以是相对其父控件RelativeLayout(layout_alignParentLeft等)。相对父控件特别有用,比如有时我们需把一个控件靠底部,就可以使用layout_alignParentBottom.
整个页面的布局,通常是一个大的LinearLayout,把页面分成几部分,比如上中下。然后再根据需要,每个部分放一个RelativeLayout,再在其中放子控件,并设定好相对的位置。
Android中好象并没有直接在程序中给控件设宽和高的属性,需要用到LayoutParams,比如
LinearLayout.LayoutParams param = (LinearLayout.LayoutParams)textView.getLayoutParams();
param.width = colWidth;
param.height = colHeight;
textView.setLayoutParams(param);
这个可是.net中的控件没有的很cool的功能,我们可以为控件的上下左右四个方向添加不同的图标,并且在程序中动态的改变。
Drawable dw_left = getResources().getDrawable(R.drawable.schedule_type);
dw_left.setBounds(0,0,dw_left.getMinimumWidth(), dw_left.getMinimumHeight());
textView.setCompoundDrawables(null, null, dw_left, null);
初学者不要一看到要自己写一个控件,就觉得很难。其实在android中还是很好实现的。有时我需要把一些控件加一些图标,或者边框之类,它本身的属性不能实现类似功能。我们只要简单的把原有的控件简单封装一下。比如我要用到带边框的EditText,EditText本身属性是不能加边框的,我们可以简单的写一个扩充的EditText类,这里主要用到onDraw(Canvas canvas)方法。我们在子类中重载这个方法,可以为控件画一些边框之类。
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
Paint paint = new Paint();
paint.setStrokeWidth(1);
paint.setStyle(Style.STROKE);
paint.setColor(android.graphics.Color.Blue);
paint.setAntiAlias(true);
RectF rectF = new RectF(2,0,this.getWidth()-2,this.getHeight()-2);
canvas.drawRoundRect(rectF, 8, 8, paint);
}
GridView和ListView是使用最多的多数据呈现控件,我们已经知道它通常重载一个Adapter类还实现数据绑定。利用这个Adapter,我们可以实现很多很炫的功能。
我想到两个方法去实现这种效果,具体哪个更好,由于没有实际的开发经验,我也不太清楚,望高手指点。
a)在Grid中onItemClick事件中实现。onItemClick(AdapterView arg0, View arg1, int arg2,long arg3)有四个参数,我们常用到的是第二和第三参数。Arg1,指的是这个子项的View,通过它,我们可以得到相应的子控件。Arg2,是指当前项在列表中的位置。
我们要改变当前选定项的状态,当然也要恢复上一个选定项的状态,这样我们需要一个页面级的中间临时变量,把上一个选定项保存起来。比如下面的代码就是把当前选定项中的一个textview的下方,加一个图标。
public void onItemClick(AdapterView arg0, View view, int position,long arg3) {
Drawable dw_left = getResources().getDrawable(R.drawable.date_convert);
dw_left.setBounds(0,0,dw_left.getMinimumWidth(), dw_left.getMinimumHeight());
TextView textView = (TextView) view.findViewById(R.id.tvtext);
textView.setCompoundDrawablesWithIntrinsicBounds(null, null, null, dw_left);
if(lastSelectedCol != null){
lastSelectedCol.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
}
lastSelectedCol = textView;
}
b) 在Adapter中实现。onItemClick事件我们还是要利用到的,这次我们要利用它的第三个参数arg2,即当前项在列表中的位置。
首先我们要给Adapter设一个属性,以便把这当前项的位置传给Adapter。
public void setSelectedCol(int position){
selectedCol = position;
}
得到了选定项的位置后,我们就可以在Adapter的getView方法中处理了。处理的方法跟上面的一样了,先得到控件,再作相应处理。
if(selectedCol == position){
//处理控件
}
最后在grid的onItemClick事件中,我们别忘了用myAdapter.notifyDataSetChanged方法去刷新控件。
比如要做一个类似iphone中短信的功能,点击编辑按钮,列表中所有的短信的左边都显示一个操作图标,点这个操作图标,右边就会增加一个删除按钮,再点删除按钮,删除当前项。这里不贴详细的代码了,只是总结一下实现要点:
a. Adpater要加一个属性,指明当ListView是在可编辑状态还是只读状态。
public void setEdit(boolean edit){
this.isEdit = edit;
}
b. Adpater中的getView方法中,根据这个isEdit属性去判断是否显示左边的图标,并是否添加相应事件。
c. 父页面的编辑按钮click事件中,动态设定Adpater中的isEdit的值。
Android虽然没有像.net中的分页控件,但分页显示数据的功能很好实现。我们只要在onScroll事件中判断listview是否滚动底部了if (firstVisibleItem + visibleItemCount == totalItemCount),然后在到底部时,动态改变数据源,增加数据源的项就行了。
如果取的是SQLite的数据,由于速度很快,我们可以直接加载。别忘了SQLiteDatabase的query方法是可以分页取数的。
如果取的是网络,可能要用到异步,在取数的同时,我们可以用一个控件显示“正在加载”。加载完后,再隐藏该控件。
程序的顶部或底的Tab控件是用得比较多的功能,很多程序都要底部有多tab,点不同的tab跳转到不同的功能模块。Android也有一个叫TabHost的控件实现该功能。具体的实现很简单,要用到TabActivity。自己的activity 需要extents TabActivity。
在使用的过程中,我发现一个问题,比如我一个Main页面,上面用到了一个tab ,点第二项打开的是A页面,然后我要从A页面跳转到B页,B页面完成操作后再返回A页面,这时问题来了,A页面由于是main页面的一个子页面,我需要下部是一直显示Tab的,但在B页面用intent到A页面后,下面的Tab不见了。我如果从B页面返回到main页面,这样默认打开的就不是A页面了。这个问题开始困惑我好久,会来在网上找到一个方法,把main页面的Tabhost控件设成一个全局的静态变量,这样在B页面运行返回到main页面的代码后面,再加上MainActivity.tabHost.setCurrentTab(1),这样main页面打开的同时,又会指向A页面了。
上面的问题解决后,又来一个新的问题,本来A页面是一个子页面,下面是显示了主页的Tab的,如果我从A页跳转到B页面,想要B页面也保留下面的tab,这应该怎么实现呢?在网上找了很久,才发现一个用GroupView实现的列子。它使用的是一个ActivityGroup页面。这里称它为BaseGroup页面。在main页面的tab选项中,点击打开的BaseGroup页面,再通过BaseGroup跳转到A页面。具体参考下面的文章。
http://hkp.iteye.com/blog/1185482
异步获取网络数据通常有两种方式,使用Handler+线程或AsyncTask方法,两种方法我都只是做了简单的试验,感觉Handler+线程思路更清晰,初学者更容易掌握。具体的实现可以参考下面的文章,写得非常详细。
http://www.cnblogs.com/JerryWang1991/archive/2012/03/09/2388312.html
通过两周的学习,总的感觉android的开发是比较好上手的,它要用到的知识面的广度应该还比不上.net的项目开发。用一两周的时间,完全可以比较轻松的掌握基本和常用的一些技巧,并做一些实际的开发了。
对于学习资源,我建议是直接看android的官方网站,特别是一些API的说明。每使用一个控件或功能前,应该首先看看它的API说明,大概的了解它有哪些方法和属性,这样就比较清楚的知道它能干些什么了,是否能满足你的需要了。
看别人的代码或sample代码,是一个很好的学习方式。Android是一个开放的平台,在网上也可以找到很多的代码。但是要真正把它变成自己的东西,无它,还是要自己试着动手,just do it!
有时间希望能跟大家更多的交流,祝好运......