没有上来写东西n久了。 刚刚这个星期完成了第一个iPad app的开发 iNotes for iPad。觉得有必要上来说说关于为什么我要开发这个app以及这个app的开发过程。因为学习了37signal和dhh所提倡的方法, promoting your thoughts by teaching people,在教别人做一个事情的时候(对我来说就是iPad的开发)来传播你的思想方法和产品。而且,刚刚昨天离开了工作3年的公司开始自己的soho旅程,没有什么不可以说的了(在职的时候,不能说太多工作上的东西)。因此,在未来的一个星期内,我会总结出开发iPad app的心得和我对iPad 软件的一些看法。
首先,先自我介绍一下吧,我是以下iPhone/iPad apps的开发者:
Rutter's Finder iphone apps
Techron2Go iphone app
VoiceCard iphone app
iNotes for iPad (Coming Soon/即将推出)
参与了iPhone开发整整一年,从一开始的好奇(在公司用自己的macbook从对obj-c一无所知到4天搞出了第一个demo給老板看,再用自己的macbook在公司开发了整整1个月,老板才答应买了一台iMac),到现在开发出了多个产品。公司从没有移动开发人员到现在的5-6个开发人员,到现在移动产品成为公司的杀手级产品,只花了一年时间。对iOS的开发太喜爱了,我把自己的未来赌在了这个平台之上。特别看完了iOS 4的api后,深信苹果的一句话,"iPhone 4 changes everything again"。这句话同样适用于iOS app开发之上,为什么?因为新的api+创意可以令你和大开发团队例如, tap tap revenge回到了同一起跑线上。
iNotes是我的第一个iPad程序,当我看到了乔教主对这个设备进行演示和了解完api document后,我想到,iPhone是在普通消费者的应用层面上带来了巨大的革命,而iPad这个设备,是即将在商业领域上带来巨大的影响甚至是革命。例如,教育界,医疗界,房地产界等等的行业应用。而连接设备和这是行业的专业人士的就是我们开发者。深深考虑了这些的时候,我觉得我必须要开发iPad的软件,iNotes就是我的第一个主意,因为最容易令大家想到的iPad的应用场合就是笔记记录。
虽然iPhone/iPad自带的Notes软件很漂亮,但是我发现,整个软件就是一个笔记本,每个记录是一页,在我使用一段时间后,问题很快就来了。例如,我在公司用它来做工作会议记录,回到家后,也用它来做家庭琐事记录,但很快的里面就开始乱七八糟了。你做下一个会议记录的时候,翻看上次记录就要在list里跳来跳去。因为,我觉得有必要做一个笔记app,里面包含不同的笔记本,例如会议记录是连续的一个本子,家庭记录是另外一个本子。这就形成了iNotes第一个功能需求,Notes are orginized in different notebooks. 默认的notes软件更像是一个便签式的记录工具,而iNotes是一个不一样的角色。
搜索了很多iPad上的笔记软件后,发现很多以手写为主的note程序,例如做得很好的Penultimate,但使用后,我立即发现这类app的缺点也非常明显。手写的确很有趣,但因为iPad的手写工具是手指头,例如写中文的精度太低了,要把字写得好,必须把字写得很大,一旦写大了,一页纸自然不能写多少东西。另外一个更大的缺点是,这些手写文字都被保存为图像,不能后来进行搜索或者格式转换,成为图像后,字的信息量就失去了。所以,iNotes的第二个功能需求就出来了,我的app要兼容手写但不提倡用户用来写文字,多数是用来画线,画图,和画出文字的重点部分。这样才能包装笔记的文字信息量,和以后的可搜索性。
当我把自己套进学生这个角色来用iNotes的时候,我会用它来记录上课笔记,例如这个学期的数学课的笔记,一个学期完后,我就有个一个数学课的笔记本子。到了期末,要和同学之间共享这个本子。因为当年学生时期做得最多的就是复印班里一些同学的笔记。这样,笔记共享这个功能就出来了,iNotes的第三大功能 - 输出PDF后通过email分享以及拷贝到pc上打印。
在这三大骨架功能确定后,我在这些基础上再添加了其他小功能,插入图片,网页快照(用来讨论和分析网页),地图快照(快速记录和分享地理信息),文本框功能(手写的字太大了,用来做说明时,不方便,可拖动的小文本框比较好)。
iNotes功能设计基本上就是这些。也是我对其需求的思考过程。这个文章就写到这里,下一文就开始谈谈开发技术上的一些心得。希望这些可以为一些希望加入这个圈子的开发者带来帮助,和为正在做开发的一些程序员带来一点共鸣,我们可以产生一个可以互动,互助的开发圈子。
iNotes的一些屏幕截图已经贴到了附件中,欢迎大家的各种意见。
新建一个Java工程,新建一个constants.properties资源文件
Java代码
1.userName = snail
2.age = 24 3.password = 123456 userName = snail
age = 24
password = 123456然后我们再建立一个类Constans.java,附上静态变量
Java代码
1.package testproperties;
2.
3.public class Constants { 4.
5. public static String userName; 6. public static int age; 7. public static String password; 8.}
package testproperties;
public class Constants {
public static String userName;
public static int age;
public static String password;
}接下来的工作就尝试着如何获取properties文件类定义的姓名、年龄和密码了,新建一个InitProperties类
Java代码
1.package testproperties;
2.
3.import java.io.FileInputStream; 4.import java.io.IOException; 5.import java.util.Properties; 6.
7.public class InitProperties { 8. private static final long serialVersionUID = -2106230733190196852L; 9.
10. public void init() 11. {
12. System.out.println("#############################加载配置信息###########################"); 13. Properties prop = new Properties(); 14.
15. //得到的是编译后的bin的目录Class.class.getClass().getResource("/").getPath(); 16.
17. //这个是绝对路径 18.// String filepath = "E:\\myeclipse6\\workspace\\XXX\\src\\testproperties\\constants.properties"; 19.
20. String filepath = Class.class.getClass().getResource("/").getPath()+"/testproperties/constants.properties" ; 21.
22. System.out.println("++++++++++++"+Class.class.getClass().getResource("/").getPath()+"+++++++++++++"); 23.
24. FileInputStream fis = null; 25. try { 26. fis = new FileInputStream(filepath); 27. prop.load(fis);
28. Constants.userName = prop.getProperty("userName"); 29. Constants.age = Integer.parseInt(prop.getProperty("age")); 30. Constants.password = prop.getProperty("password"); 31. System.out.println(Constants.userName+Constants.age+Constants.password);;
32. System.out.println("#############################加载配置信息完成###########################"); 33. }
34. catch (IOException e) { 35. System.out.println("加载constants.properties文件失败,文件不存在后者路径不正确! "); 36. e.printStackTrace();
37. }
38. }
39. public static void main(String[] args) { 40. InitProperties ip = new InitProperties(); 41. ip.init();
42. }
43.}
package testproperties;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
public class InitProperties {
private static final long serialVersionUID = -2106230733190196852L;
public void init()
{
System.out.println("#############################加载配置信息###########################");
Properties prop = new Properties();
//得到的是编译后的bin的目录Class.class.getClass().getResource("/").getPath();
//这个是绝对路径
// String filepath = "E:\\myeclipse6\\workspace\\XXX\\src\\testproperties\\constants.properties";
String filepath = Class.class.getClass().getResource("/").getPath()+"/testproperties/constants.properties" ;
System.out.println("++++++++++++"+Class.class.getClass().getResource("/").getPath()+"+++++++++++++");
FileInputStream fis = null;
try {
fis = new FileInputStream(filepath);
prop.load(fis);
Constants.userName = prop.getProperty("userName");
Constants.age = Integer.parseInt(prop.getProperty("age"));
Constants.password = prop.getProperty("password");
System.out.println(Constants.userName+Constants.age+Constants.password);;
System.out.println("#############################加载配置信息完成###########################");
}
catch (IOException e) {
System.out.println("加载constants.properties文件失败,文件不存在后者路径不正确! ");
e.printStackTrace();
}
}
public static void main(String[] args) {
InitProperties ip = new InitProperties();
ip.init();
}
}
现在附上集中在jsp、Java、和servlet中获取路径的方法:(引用自http://zhidao.baidu.com/question/86179810.html?fr=qrl&cid=93&index=5)
1.jsp中取得路径:
以工程名为TEST为例:
(1)得到包含工程名的当前页面全路径:request.getRequestURI()
结果:/TEST/test.jsp
(2)得到工程名:request.getContextPath()
结果:/TEST
(3)得到当前页面所在目录下全名称:request.getServletPath()
结果:如果页面在jsp目录下 /TEST/jsp/test.jsp
(4)得到页面所在服务器的全路径:application.getRealPath("页面.jsp")
结果:D:\resin\webapps\TEST\test.jsp
(5)得到页面所在服务器的绝对路径:absPath=new java.io.File(application.getRealPath(request.getRequestURI())).getParent();
结果:D:\resin\webapps\TEST
2.在类中取得路径:
(1)类的绝对路径:Class.class.getClass().getResource("/").getPath()
结果:D:/TEST/WebRoot/WEB-INF/classes/pack/
(2)得到工程的路径:System.getProperty("user.dir")
结果:D:\TEST
3.在Servlet中取得路径:
(1)得到工程目录:request.getSession().getServletContext().getRealPath("") 参数可具体到包名。
结果:E:\Tomcat\webapps\TEST
(2)得到IE地址栏地址:request.getRequestURL()
结果:http://localhost:8080/TEST/test
(3)得到相对地址:request.getRequestURI()
结果:/TEST/test
Animations使用(4)
LayoutAnimationController的使用方法(与ListView结合使用为例)
什么是LayoutAnimationController
1 LayoutAnimationController用于为一个layout里面的控件,或者是一个ViewGroup里面的控件设置动画效果
2 每一个控件都有相同的动画效果
3 这些控件的动画效果在不同的时间显示出来
4 LayoutAnimationController可以在xml文件中设置,也可以在代码中设置
在XML中使用LayoutAnimaionController
1 在res/anim文件夹中创建一个文件,名为list_anim_layout.xml
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android" android:delay="0.5" android:animationOrder="random" android:animation="@anim/list_anim" />
注意到list_anim这个xml文件,其中配置了动画效果,也就是一个动画配置文件(见3中)
<set>
<alpha...>
</set>
2 在布局文件中为ListView添加如下配置(就是在<listview>标签中添加一个属性)
android:layoutAnimation="@anim/list_anim_layout"
在代码中使用LayoutAnimationController
1 创建一个Animation对象: 可以通过装载xml,也可以直接使用Animation的构造函数创建Animation对象 2 创建LayoutAnimationController对象 LayoutAnimationController lac=new LayoutAnimationController(animation); 3 设置控件显示顺序 lac.setOrder(LayoutAnimationController.ORDER_NORMAL); 4 为ListView设置LayoutAnimationController属性: listView.setLayoutAnimation(lac);
AnimationListener的使用方法
什么是AnimationListener
1 Animation是一个监听器
2 该监听器在动画执行的各个阶段会得到通知,从而调用相应的方法
3 主要包含下面的三个方法
onAnimationEnd(Animation animation)
onAnimationRepeat(Animation animation)
onAnimationStart(Animation animation)
使用方法:
animation.setAnimationListener(new XxxAnimationListener);
其中XxxAnimationListener继承AnimationListene
在其中实现三个onXXX方法