存档

2011年8月 的存档

Android应用之个人应用软件开发(4)【深度UI设计自定义控件】

2011年8月19日 没有评论

我们知道在android系统中自带的控件也有不少,大部分控件的我们其实可以深度设计扩展,经过我们精心设计出来的控件,那就是自定义控件了。就像做其他应用程序一样,我们日积月累做的时间长了,为了方便使用我们可以自定义一些自己UI或者功能型的控件。根据不同的需要定制不同的控件类型,那么简单说一下我怎么来设计这个理财软件的列表UI,其实我就想方便的进行统计和查阅,普通的单行列表已经满足不了我的需求,我需要的是分级的列表:

父级下面还还有自己的列表,可以伸展、收缩、效果很赞很整!!喜欢的顶起走。。。

我简单的设计了几个图和背景来暂时一下这个分级列表。

下面就是具体的UI设计了,因为是在自带的控件上拓展的,那就重点说一下ExpandableListView这个控件。它的原始模样是这样的:

listcost.xml

Android应用之个人应用软件开发(4)【深度UI设计自定义控件】

具体的UI设计大图及代码:

Android应用之个人应用软件开发(4)【深度UI设计自定义控件】

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android
="http://schemas.android.com/apk/res/android"
android:orientation
="vertical"
android:layout_width
="match_parent"
android:layout_height
="match_parent" android:background="@drawable/licai_bd" android:weightSum="1">
<LinearLayout
android:layout_width
="fill_parent"
android:layout_height
="wrap_content">
<Button android:text=""
android:layout_width
="wrap_content"
android:layout_height
="wrap_content"
android:background
="@drawable/btn_browser"
android:id
="@+id/bt_goback"></Button>
<TextView
android:layout_width
="wrap_content"
android:layout_marginLeft
="3px"
android:textColor
="@color/clanse"
android:text
="TextView"
android:layout_height
="wrap_content"
android:layout_gravity
="center"
android:id
="@+id/tv_aboutthismoth">
</
TextView>
</LinearLayout>
<ExpandableListView
android:layout_width
="fill_parent"
android:layout_height
="wrap_content"
android:scrollbars
="none"
android:id
="@+id/listmonthcostid"
>
</ExpandableListView>
</LinearLayout>

自定义控件UI设计,首先做一下一级栏目的效果及代码:

lc_listview.xml

Android应用之个人应用软件开发(4)【深度UI设计自定义控件】

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android
="http://schemas.android.com/apk/res/android"
android:orientation
="horizontal"
android:layout_width
="fill_parent"
android:layout_height
="wrap_content"
android:background
="@drawable/listview_bg">
<TextView
android:layout_width
="match_parent"
android:id
="@+id/tv_fristtitel"
android:layout_height
="wrap_content"
android:text
="绑定数据"
android:layout_gravity
="center"
android:textSize
="16dp"
android:layout_margin
="8dp"
android:textColor
="@color/clanse2"
>
</TextView>
</LinearLayout>

自定义控件子级列表的代码及设计图:

lc_listchild.xml

Android应用之个人应用软件开发(4)【深度UI设计自定义控件】

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android
="http://schemas.android.com/apk/res/android"
android:orientation
="horizontal"
android:layout_width
="fill_parent"
android:layout_height
="wrap_content"
android:background
="@drawable/listchild_bg" android:gravity="top">

<LinearLayout
android:layout_width
="wrap_content"
android:layout_height
="wrap_content"
android:layout_centerVertical
="true"
android:layout_marginLeft
="10dp"
android:orientation
="vertical" android:id="@+id/linearLayout1">
>
<ImageView
android:layout_width
="wrap_content"
android:src
="@drawable/xgg"
android:layout_height
="wrap_content"
android:id
="@+id/imageView1"
android:layout_alignTop
="@+id/linearLayout1"
android:layout_alignParentLeft
="true"></ImageView>

</LinearLayout>
<LinearLayout
android:layout_width
="wrap_content"
android:layout_height
="wrap_content"
android:layout_centerVertical
="true"
android:layout_marginLeft
="60dp"
android:orientation
="vertical" android:id="@+id/linearLayout2">
>
<TextView
android:layout_width
="wrap_content"
android:layout_height
="wrap_content"
android:textColor
="@color/clanse2"
android:text
="绑定数据"
android:textSize
="16dp" android:id="@+id/txt_fristtext">
</TextView>

<TextView
android:layout_width
="wrap_content"
android:layout_height
="wrap_content"
android:textColor
="@color/clanse"
android:text
="绑定数据"
android:textSize
="14dp" android:id="@+id/txt_txetinfos">
</TextView>
</LinearLayout>
<LinearLayout
 android:layout_width
="wrap_content"
android:id
="@+id/linearLayout3"
android:layout_height
="wrap_content"
android:layout_centerVertical
="true"
android:layout_alignParentRight
="true"
android:layout_marginRight
="23dp">
<ImageView
android:layout_width
="wrap_content"
android:src
="@drawable/rmb_bg"
android:layout_height
="wrap_content"
android:id
="@+id/imageView2">
</
ImageView>
<TextView android:text="TextView"
android:layout_marginLeft
="5dp"
android:textColor
="@color/clanse"
android:layout_width
="wrap_content"
android:layout_height
="wrap_content"
android:id
="@+id/txt_rmb">
</
TextView>
</LinearLayout>

</RelativeLayout>

好了,UI全部写好了,大家可以意淫一下我们的效果图,嘿嘿。我感觉如果出来的效果会很整!!!接下来我们要写自定义控件的代码了,首先我们要写一个类;

类名自定义,不过一定要继承BaseExpandableListAdapter这个控件的基类。因为我们相当于重构。所以引用它原来的接口来直接写方法了。我们要知道几个点首先我们模仿的是一个分级的菜单列表,那么就有一级和二级,之所以我们之前用BaseExpandableListAdapter这个类得图形是因为它本就具有这样的造型,只不过我们把他里面的核心元素替换,我说的不专业,但是比较通俗易懂,下面具体看代码,我们定义一下基本的属性;看看哪些是必备的。

先从我们设计的主页面开始listcost.xml对应listcost类:

    final static String F_ListInfo= "fristlistinfo";
final static String C_ListInfo = "childlistinfo";
final static String RmbInfo = "rmbinfo";
SqliteCommen sqlc;//数据库
listchidinfo mylistinfo;//自定义控件类申明

接下来看看
listchidinfo 是怎么写的 :
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.TextView;

public class listchidinfo extends BaseExpandableListAdapter {

private Context ct_fristinfo;
List
<String> frist_titel =new ArrayList<String>();
List
<List<Map<String,String>>> list_child = new ArrayList<List<Map<String,String>>>();

///构造函数初始化内容
public listchidinfo(Context context,List<String> a_frist_titel,List<List<Map<String, String>>> a_listchild)
{
this.ct_fristinfo=context;
this.frist_titel = a_frist_titel;
this.list_child = a_listchild;
}


public Object getChild(int groupPosition, int childPosition) {
// TODO Auto-generated method stub
return list_child.get(groupPosition).get(childPosition).get(listcost.F_ListInfo).toString();
}


public long getChildId(int groupPosition, int childPosition) {
// TODO Auto-generated method stub
return childPosition;
}


public View getChildView(int groupPosition, int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
View view = convertView;
if(view == null){
LayoutInflater inflater
= (LayoutInflater)ct_fristinfo.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view
= inflater.inflate(R.layout.lc_listchild, null);
}
final TextView tetfristext = (TextView) view.findViewById(R.id.txt_fristtext);
tetfristext.setText(list_child.get(groupPosition).get(childPosition).get(listcost.F_ListInfo).toString());
final TextView txttxetinfos = (TextView) view.findViewById(R.id.txt_txetinfos);
txttxetinfos.setText(list_child.get(groupPosition).get(childPosition).get(listcost.C_ListInfo).toString());
final TextView txtrmb = (TextView) view.findViewById(R.id.txt_rmb);
txtrmb.setText(list_child.get(groupPosition).get(childPosition).get(listcost.RmbInfo).toString());

return view;
}


public int getChildrenCount(int groupPosition) {
// TODO Auto-generated method stub
return list_child.get(groupPosition).size();
}


public Object getGroup(int groupPosition) {
// TODO Auto-generated method stub
return frist_titel.get(groupPosition).toString();
}


public int getGroupCount() {
// TODO Auto-generated method stub
return frist_titel.size();
}


public long getGroupId(int groupPosition) {
// TODO Auto-generated method stub
return groupPosition;
}


public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
View view
= convertView;
//将原来的样式替换新样式
if(view == null){
LayoutInflater inflater_new
= (LayoutInflater)
ct_fristinfo.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view
= inflater_new.inflate( R.layout.lc_listview , null);
}
TextView text_titel
= (TextView) view.findViewById(R.id.tv_fristtitel);
text_titel.setText(getGroup(groupPosition).toString());
return view;
}


public boolean hasStableIds() {
// TODO Auto-generated method stub
return false;
}


public boolean isChildSelectable(int groupPosition, int childPosition) {
// TODO Auto-generated method stub
return false;
}

}

 里面重要的就是将新样式R.layout.lc_listview替换原来的样式,并进行新的控件R.ID的赋值。将新的控件的方法也重新绑定上。通过做这个实例可以衍生到其它控件也可以采用这样的方法进行扩展自定义控件。只要自己想得到,那就有百变的造型UI,不是么?今天换一套明天换一套······

 然后接下来就是UI里面的数据绑定和书写了,下面是从之的数据表添加来的数据,需要将数据按照月份来绑定,首先弄了2个功能:

 1,上个月的开资明细列表情况

 2,本月的开资明细列表情况

 然后两月的总开资进行对比,嗯,这个就比较人性话了,目前我想到的功能就只有这么方便,这么多,太复杂了我自己不好用,其它人不好用,不过肯定有一些小毛病的,那是软件版本2.0的事,以后肯定会跟大家说怎么做版本2.0的问题的,任何一款应用软件都会遇到2.0问题···到时候说个详细吧,现在就不批跨了!

listcost.java

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import android.app.Activity;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.text.format.Time;
import android.view.Window;
import android.widget.ExpandableListView;
import android.widget.TextView;

public class listcost extends Activity {

//数据库访问基类
SqliteCommen sqlc;

final static String F_ListInfo= "fristlistinfo";
final static String C_ListInfo = "childlistinfo";
final static String RmbInfo = "rmbinfo";
private int lastmonthspend;
private int thismonthspend;
private String str_lastmonthcount;
private String str_thismonthcount;
listchidinfo mylistinfo ;
ExpandableListView listmonthcost ;
List
<String> a_frist_titel = new ArrayList<String>();
List
<List<Map<String, String>>> a_listchild = new ArrayList<List<Map<String, String>>>();

public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//窗体状态设置-设置为无标题栏状态【全屏】
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.listcost);
//自定义控件
listmonthcost = (ExpandableListView)findViewById(R.id.listmonthcostid);
sqlc
= new SqliteCommen(this);
SQLiteDatabase db
= sqlc.getReadableDatabase();

TextView tv_Allspend
= (TextView)findViewById(R.id.tv_aboutthismoth);
final String[] AllFeild =
{
PublicDataCost.ID,
PublicDataCost.Field_1_1,
PublicDataCost.Field_1_2,
PublicDataCost.Field_1_3,
PublicDataCost.Field_1_4,
PublicDataCost.Field_1_5,
PublicDataCost.Field_1_6
};

Time t
= new Time();
t.setToNow();
int nowmonth = t.month + 1;
String lastmonth_datetime
= t.year +"" +t.month+ "";
String thismonth_datetime
= t.year +"" +nowmonth+ "";

Cursor c_lastmonth
= db.query(PublicDataCost.Tb_Name_1 , AllFeild, "DateTimes like '%"+lastmonth_datetime+"%'"
,
null, null, null, null);
c_lastmonth.moveToFirst();
List
<Map<String, String>> lastmonthlist = new ArrayList<Map<String, String>>();
if(c_lastmonth.getCount()>0)
{
for(int i=0; i<c_lastmonth.getCount() ; i++)
{
lastmonthlist.add(
new HashMap<String, String>());
lastmonthlist.get(i).put(F_ListInfo, c_lastmonth.getString(
6).toString());
int fan = Integer.parseInt(c_lastmonth.getString(1))
+
Integer.parseInt(c_lastmonth.getString(2))+Integer.parseInt(c_lastmonth.getString(3));
lastmonthlist.get(i).put(C_ListInfo,
"饭:"+fan +" 购:"+c_lastmonth.getString(4)+ "日:"+c_lastmonth.getString(5));
int lastcost = Integer.parseInt(c_lastmonth.getString(1))
+
Integer.parseInt(c_lastmonth.getString(2))+Integer.parseInt(c_lastmonth.getString(3))
+
Integer.parseInt(c_lastmonth.getString(4))+Integer.parseInt(c_lastmonth.getString(5));
lastmonthlist.get(i).put(RmbInfo,
""+lastcost);
lastmonthspend
+=lastcost;
str_lastmonthcount
= ""+lastmonthspend;
c_lastmonth.moveToNext();
}

}
else
{
lastmonthlist.add(
new HashMap<String, String>());
lastmonthlist.get(
0).put(F_ListInfo, lastmonth_datetime+"暂无理财");
lastmonthlist.get(
0).put(C_ListInfo, "暂无理财信息!");
lastmonthlist.get(
0).put(RmbInfo, "¥0.00");
str_lastmonthcount
= "¥0.00";
}
a_frist_titel.add(
"上月理财 总开销:" + str_lastmonthcount);
c_lastmonth.close();

Cursor c
= db.query(PublicDataCost.Tb_Name_1 , AllFeild, "DateTimes like '%"+thismonth_datetime+"%'"
,
null, null, null, null);
c.moveToFirst();
List
<Map<String, String>> childlist = new ArrayList<Map<String,String>>(c.getCount());
for(int i=0; i<c.getCount() ; i++)
{
childlist.add(
new HashMap<String, String>());
childlist.get(i).put(F_ListInfo, c.getString(
6).toString());
int fan = Integer.parseInt(c.getString(1))+Integer.parseInt(c.getString(2))+Integer.parseInt(c.getString(3));
childlist.get(i).put(C_ListInfo,
"饭:"+fan +" 购:"+c.getString(4)+ "日:"+c.getString(5));
int lastcost = Integer.parseInt(c.getString(1))+Integer.parseInt(c.getString(2))
+Integer.parseInt(c.getString(3))+Integer.parseInt(c.getString(4))+Integer.parseInt(c.getString(5));
childlist.get(i).put(RmbInfo,
""+lastcost);
thismonthspend
+=lastcost;
str_thismonthcount
= ""+thismonthspend;
c.moveToNext();
}

c.close();
a_frist_titel.add(
"本月理财 总开销:" + str_thismonthcount);
db.close();


a_listchild.add(lastmonthlist);
a_listchild.add(childlist);
mylistinfo
= new listchidinfo(listcost.this, a_frist_titel , a_listchild);

//载入自定义控件
listmonthcost.setAdapter(mylistinfo);
// 去掉系统自带的按钮分隔线
listmonthcost.setGroupIndicator(null);
listmonthcost.setDivider(
null);

// 展开所有二级列表
int groupCount = mylistinfo.getGroupCount();
for (int i = 0; i < groupCount; i++) {
listmonthcost.expandGroup(i);
}

tv_Allspend.setText(
"您本月总开资:"+ str_thismonthcount);
}
}

好了好了,代码写得很整了,不知道效果整不整。

先跑一跑吧!!!

看图:

Android应用之个人应用软件开发(4)【深度UI设计自定义控件】

这个是收起来的效果,下面看看展开的效果整不整?

Android应用之个人应用软件开发(4)【深度UI设计自定义控件】

如果多录几条数据进去可以上下拉动的,效果也是一样的···

Android应用之个人应用软件开发(4)【深度UI设计自定义控件】

下一次发文章,我就发一下关于android图像处理的一些东西,我个人觉得比较犀利,以前我就做sl游戏开发,还有flax游戏也做过,但是这个图形的差别还是很大的,我预想的做法是做柱状图控件那种。。。再看吧,希望能和各位android开发爱好者一起学习心得知识。

分类: 未分类 标签:

Can I overlay HTML on a Unity window?

2011年8月17日 没有评论

I’m working on a website that has rich content displayed in a Unity window. However, this Unity window sits under a navigation menu that has drop-downs, and drop-down menus are going behind the Unity window.

With Flash, this was easily solved by setting the wmode property to transparent. Is there a similar solution with Unity, or a different solution entirely that works and allows me to place standard HTML over the top of Unity windows?

Thanks in advance.

Some related posts on unity forums

http://forum.unity3d.com/threads/22270-Unity-Flash-Div-issue-in-Browser

http://answers.unity3d.com/questions/10599/does-unity-have-an-embed-parameter-equivalent-to-f.html

The answer: there isn’t a way to set some equivalent of the flash wmode=transparent but there is a workaround with setting the css visibility:hidden (or resizing to width:1px & height:1px)

So, kind of a hack, but you could set the menu’s hover event to change visibility of the unity window as a workaround.

Old post, but this might help someone.
I can get HTML to display over the Unity window in Safari, Chrome, Firefox on my Mac and Windows IE 10 & 11 with a div. I can get it to always display with an iFrame in all windows. The trick with the iFrame is not all browsers support transparent iFrame, so sometimes you will see the iFrame, but not transparent. IE 8 does not support transparency at all and if its set to be on, then the iFrame will not display above the Unity screen.

DIV:
I basically float a DIV over the unity content. Content can be either plain HTML or Flash. Opacity seems to help make it work.
My situation is we have a menu that needs to display over the top part of the Unity window. Note that Unity is NOT in full screen mode, but sits in a Div. Maybe this is why I can do it??
Anyway- the code looks something like this:

<div>
   <div><unity object></div>
   <div style="position:absolute; opacity:.9">html or flash content</div>
</div>

The iFrame approach works fine for content that is always the same size, but if you have something like a combobox, then its an issue because the window needs to first resize the height to show the drop down, and then the iFrame background will cover all the content. A hack, is to open a SECOND iframe with the combobox. Sucks, but that is the way I had to do it..

hth-
Dustin

分类: cocos2d, stackoverflow精选 标签:

Should I subclass CCSprite, CCNode, or NSObject?

2011年8月16日 没有评论

I see that certain texts always seem to subclass CCSprite. I read somewhere that it is not good to do that and that it is better to start with something basic. I wanted to find out what the pro game developers do in terms of game structure. That is subclass CCSprite or add CCSprite in a NSObject class ETC.

I hope my question makes sense.

Your question definitely makes sense.

It’s fundamentaly an architecture question. If your game is mainly based on “animation”, I’d go for subclassing CCSprite. If your game is mainly based on some logic, maybe a RPG or whatever else, then the screen representation is in fact just one of the possible views of the game state. Therefore, it should be, in my opinion, part of an object in the tree of objects that represents your game state.

In other words: if your game state is essentially a scene, then subclass CCSprite, because Cocos2D is probably way better than you at managing scenes. If your game state is “something else”, you probably should consider building your own representation of that state, and make your sprite part of your game object. This will also allow you to “switch” graphics engines if you decide to change rendering. For example, you might be doing a RPG with a 2D representation in Cocos2D. After a while, you show your demo to Ubisoft and they fall in love with it and give you 20 million dollars to finish it, but they request a 3D rendering. If you went for subclassing CCSprite, you have to redo all the game. If you went for integrating the CCSprite/CCNode in a NSObject-derived class, you’re good to go.

Of course, that example is slightly exaggerated for the purpose of … example :D

If you have this question at this venture of your Cocos2D journey, subclass CCSprite and be done with it. You will not be creating anything right now that will require the advanced techniques of fine-tuned classes. I say this not as an insult to your abilities, but as a person who once had this question.

When you start to wonder if you need to rewrite the OpenGL method calls of CCNode, then you’ll be at a point where you’ll need to carefully consider your subclassing options. Subclassing CCSprite grants you all the methods and properties of everything lower, giving you the ability to discover, learn, and move forward.

In short: subclass CCSprite.

My preference is to subclass CCNode almost exclusively.

I would only ever subclass CCSprite, CCLabel and other internal Cocos2D classes if I needed the sprite, label or whatever to behave slightly differently from the base implementation. And subclassing would be a last resort measure if a category is insufficient. What most Cocos2D developers apparently don’t understand is that CCSprite is in itself a complete class that does not need to be extended (subclassed) for representing game objects. But it’s all too easy to fall into this habit because by creating a CCSprite subclass you get the visuals and you have a container for your game logic code. It’s just not very OOP to do so.

If you think about it, as soon as you add some sort of game logic code to a CCSprite, it’s not really just a CCSprite anymore, or is it? One good way to think about it is this: if you subclass a class (name it MyClass) and add custom code to it, would it make a lot of sense to subclass MyClass for other purposes, too? If not, then you shouldn’t subclass.

To go with the widely used OOP analogy of the “Car” class: you subclass “Car” to make more specialized but still generic classes like “SportsCar”, “Truck”, “Van” but you wouldn’t subclass “Car” to create a “Porsche 911 V-Turbo Model 6″. Why not? Because the “SportsCar” class has all the aspects to create an instance of a SportsCar that then becomes a “Porsche 911 V-Turbo Model 6″.

The other thing you have to consider is that a “Porsche 911 V-Turbo Model 6″ would be a highly specialized class which doesn’t have any other purpose than to define what that very specific car is about. It wouldn’t make any sense to subclass the “Porsche 911″ class because it has essentially lost its generic attributes and replaced them with very specific implementation details. If you have a class that you can’t reasonably subclass any further, you’ve created a dead-end in your class hierarchy and are essentially writing functional code, not object-oriented code. Still, it’s ok for simple games but it’ll come back to haunt you if you dare to do more.

To summarize: you would subclass CCSprite only if your intention is to make a more specialized but still generally useable type of CCSprite. One example for that would be CCLabelTTF, which subclasses from CCSprite. It only adds the ability to create the CCSprite texture at runtime from a font and string. Another example for subclassing CCSprite would be if you needed a CCSprite that would update its texture from Google Maps to resemble a maps tile based on longitude and latitude coordinates and zoom level. It would still essentially be a dumb object whose only purpose is to display a rectangular image at a certain position. That’s what a CCSprite is. A dumb object that displays a texture at a certain position.

The question really is about this: is (“is a”) your game object a sprite, or does it have (“has a”) a sprite for its visual representation? The answer should always be the latter. The common rule for subclassing is the “is a” relationship, in case of “has a” it’s time for the composite pattern. If in doubt, and both seem to apply, always err on the “has a” side because that always works.

Why would I say that a game object is not a sprite, but has a sprite? Clearly both are applicable. The answer: the game object “is a” sprite only as long as it can be represented by a single sprite and nothing else. But in fact, your game object might have to be represented by multiple sprites, or a sprite, a label and some particle effects. That means the “is a” relationship is much more likely to break as the app is being developed, and that means additional refactoring work.

By using a CCNode as the base class for your game objects, and adding the visual nodes onto that base node, you can also use the base node as the controller object for the game object’s view(s). Which means it’ll better conform to the Model-View-Controller (MVC) pattern.

Finally I wouldn’t subclass NSObject for anything that should be in the cocos2d view hierarchy, or keeps a reference to something that’s in the cocos2d view hierarchy. For the simple reason that NSObject subclasses don’t offer any of the standard features of a CCNode (scheduling, adding child nodes, relative positioning of child nodes) and most importantly, it’s difficult to use NSObject subclasses together with Cocos2D’s rather automatic memory management of node classes.

Without going into detail, the simple rule is that if a subclass has an instance variable that is a Cocos2D node, it should itself be a Cocos2D node so that memory management and all other aspects are easy and foolproof. As far as Cocos2D is concerned, the CCNode class is the root class for the view hierarchy, so it resembles the UIResponder class with the ability to take on the role of the UIView and/or UIViewController classes (both subclass from UIResponder by the way) on occassions.

In short: subclass CCNode, then use composition/aggregation pattern for the visual aspects of the class.

in my opinion, object in game is not sprite. Sprite is representation for object, it’s mean you need create GameObject subclass NSObject ( maybe CCNode)..

To summarize: subclass NSObject or CCSprite is class structure, you need using your code style.

分类: cocos2d, stackoverflow精选 标签:

Android应用之个人应用软件开发(3)【SQLite数据库及理财功能实现】

2011年8月16日 没有评论

  Android给我们提供 Sqlite这种轻量级数据库,并提供了一些数据操作访问的类库.如:SQLiteOpenHelper 主要是处理打开、创建、更新等方法的类库。

  有onCreate() onOpen() onUpgarde(db,int ,int) 等方法,还有几个重要的和常用的类也要说一下,就是SqliteDataBase,提供操作SQLite的增、查、删、改等基本方法。还有就是ContentValues ,用来维持当前已打开的数据库的相关数据,当然也提供了增、查、删、改,只不过是在当前数据中。那么先实现创建,和提供的一些自定义的接口,方便我们以后使用,引用方便。

 一些数据字段的都放在这个接口中:

public interface PublicDataCost {
//定义数据库名称
String DATABASE_NAME = "ZisouBaseDate";
int DATABASE_VERSION = 1;

//路径地址
String DB_PATH =
"/data/data/Zisou.Soft.mini/databases";
String PATH
= "/databases";
String DB_NAME
= "zisoubasedate.db";

//定义共享优先数据及基础字段
String MY_RMBCost ="MY_RMBCost";
String TodayTime
="TodayTime";

//Sqlite数据库基础字段
//公有字段
String ID = "id";
//TodaySpend表结构
String Tb_Name_1 = "TodaySpend";
String Field_1_1
= "Morning";
String Field_1_2
= "Noon";
String Field_1_3
= "Night";
String Field_1_4
= "OtherSpend";
String Field_1_5
= "DailySpend";
String Field_1_6
= "DateTimes";
}
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.view.View.OnClickListener;
public class SqliteCommen extends SQLiteOpenHelper {

//定义增,改,删,清除字段
OnClickListener dbl_add = null;
OnClickListener dbl_update
= null;
OnClickListener dbl_delete
= null;

public SqliteCommen(Context context) {
super(context, PublicDataCost.DATABASE_NAME, null, PublicDataCost.DATABASE_VERSION);
// TODO Auto-generated constructor stub
}

@Override
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
String sql = "CREATE TABLE " + PublicDataCost.Tb_Name_1 + " ("
+ PublicDataCost.ID + " INTEGER primary key autoincrement, "
+ PublicDataCost.Field_1_1 + " text not null, "
+ PublicDataCost.Field_1_2 + " text not null, "
+ PublicDataCost.Field_1_3 + " text not null, "
+ PublicDataCost.Field_1_4 + " text not null, "
+ PublicDataCost.Field_1_5 + " text not null, "
+ PublicDataCost.Field_1_6 + " text not null "
+ ");";
db.execSQL(sql);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub

}
}

写好简单的基本的数据库的基本方法,在的程序中也要使用到一些必不可少的方法,那可以通用写在Commen类里面。

    SqliteCommen sqlc;

private boolean addflag = false;

private int spinnerid;
sqlc = new SqliteCommen(this);
SQLiteDatabase db = sqlc.getReadableDatabase();

dbl_add的监听事件注册,在这里需要考虑什么时候需要添加,什么时候需要修改,那就需要两个条件,一个就是标识,和修改的ID值,当通过Sprinner下拉表传递过来的值将其绑定绑定在EeitView控件上,然后标识Button.setText()值为“修改”。addflag = true 来判断修改和删除。

        sqlc.dbl_add = new OnClickListener() {

public void onClick(View v) {
if(addflag == false)
{
//添加
Cursor c = db.query(PublicDataCost.Tb_Name_1, AllFeild, "DateTimes='" + str + "'", null, null, null, null);
if(c.getCount()>0)
{
Toast.makeText( todayspend.
this , "今天已经添加账单,你可以修改今日账单!", Toast.LENGTH_SHORT).show();
}
else
{
ContentValues cv
= new ContentValues();
cv.put( PublicDataCost.Field_1_1 , tv_Morning.getText().toString());
cv.put( PublicDataCost.Field_1_2 , tv_noon.getText().toString());
cv.put( PublicDataCost.Field_1_3 , tv_Night.getText().toString());
cv.put( PublicDataCost.Field_1_4 , tv_OtherSpend.getText().toString());
cv.put( PublicDataCost.Field_1_5 , tv_DailySpend.getText().toString());
cv.put( PublicDataCost.Field_1_6 , str);
SQLiteDatabase db
= sqlc.getReadableDatabase();
db.insert(PublicDataCost.Tb_Name_1,
null, cv);
db.close();
Toast.makeText( todayspend.
this , "添加成功!", Toast.LENGTH_SHORT).show();
onCreate(savedInstanceState);
}
c.close();
}
else
{
//修改
ContentValues cv = new ContentValues();
cv.put( PublicDataCost.Field_1_1 , tv_Morning.getText().toString());
cv.put( PublicDataCost.Field_1_2 , tv_noon.getText().toString());
cv.put( PublicDataCost.Field_1_3 , tv_Night.getText().toString());
cv.put( PublicDataCost.Field_1_4 , tv_OtherSpend.getText().toString());
cv.put( PublicDataCost.Field_1_5 , tv_DailySpend.getText().toString());
String sqlwhere
= PublicDataCost.ID + " = " + spinnerid;
SQLiteDatabase db
= sqlc.getReadableDatabase();
db.update(PublicDataCost.Tb_Name_1, cv, sqlwhere ,
null);
db.close();
onCreate(savedInstanceState);
Toast.makeText( todayspend.
this , "修改成功!", Toast.LENGTH_SHORT).show();

}
}
};

然后就是Spinner的绑定和注册了,先将数据库里面的日期取出来,在SetAdapter中绑定,R.layout.simple_dropdown_item_1line,当然也可以自己定义里面的东西,比如图文结合的下拉列表,在绑定的同时也把Spinner中的setSelection默认选择值给赋值一下。显示从库中出来的最后一条数据。最后再注册事件中将spinnerid = Integer.parseInt(c.getString(0));赋值,以便修改时候用到。

//将事件绑定到按钮
bt_addspend.setOnClickListener(sqlc.dbl_add);
//绑定列表
Cursor c = db.query( PublicDataCost.Tb_Name_1 , new String[] {PublicDataCost.Field_1_6}, null, null, null , null, null);
c.moveToFirst();
CharSequence[] cslist
= new CharSequence[c.getCount()];
for(int i=0;i<cslist.length;i++)
{
cslist[i]
=c.getString(0);
c.moveToNext();
}
c.close();
Spinner sp
= (Spinner)findViewById(R.id.spinner1);
sp.setAdapter(
new ArrayAdapter<CharSequence>(this,android.R.layout.simple_dropdown_item_1line,cslist));
sp.setSelection(cslist.length
-1);
//注册事件
sp.setOnItemSelectedListener(new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent ,View view, int position, long id){
String todaydatetime
= ((Spinner)parent).getSelectedItem().toString();
Cursor c
= db.query(PublicDataCost.Tb_Name_1, AllFeild, "DateTimes='" + todaydatetime + "'", null, PublicDataCost.Field_1_6, null, PublicDataCost.Field_1_6);
c.moveToFirst();
spinnerid
= Integer.parseInt(c.getString(0));
tv_Morning.setText(c.getString(
1));
tv_noon.setText(c.getString(
2));
tv_Night.setText(c.getString(
3));
tv_OtherSpend.setText(c.getString(
4));
tv_DailySpend.setText(c.getString(
5));
c.close();
}

public void onNothingSelected(AdapterView<?> arg0) {
// TODO Auto-generated method stub

}
});

然后最后就是将今日和昨日的理财信息给显示出来,我就贴一下全部的代码吧:

Android应用之个人应用软件开发(3)【SQLite数据库及理财功能实现】Android应用之个人应用软件开发(3)【SQLite数据库及理财功能实现】View Code

import android.app.Activity;
import android.content.ContentValues;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.text.format.Time;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemSelectedListener;

public class todayspend extends Activity {


SqliteCommen sqlc;
//SQLiteOpenHelper
private boolean addflag = false; //标识
private int spinnerid;

public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.todayspend);
sqlc
= new SqliteCommen(this);
final TextView vt_qdt = (TextView)findViewById(R.id.tv_qdt);
final SQLiteDatabase db = sqlc.getReadableDatabase();
final EditText tv_Morning = (EditText)findViewById(R.id.tv_Morning);
final EditText tv_noon = (EditText)findViewById(R.id.tv_noon);
final EditText tv_Night = (EditText)findViewById(R.id.tv_Night);
final EditText tv_OtherSpend = (EditText)findViewById(R.id.tv_OtherSpend);
final EditText tv_DailySpend = (EditText)findViewById(R.id.tv_DailySpend);
final Button bt_addspend = (Button)findViewById(R.id.bt_addspend);
final Button bt_qiandao2 = (Button)findViewById(R.id.bt_qd2);
final SharedPreferences my_rmb_data = getSharedPreferences(PublicDataCost.MY_RMBCost, 0);
final String nowtime = my_rmb_data.getString(PublicDataCost.TodayTime, "").toString();
TextView jrzkx_0
= (TextView)findViewById(R.id.jrzkx_0);
TextView jrzkx_01
= (TextView)findViewById(R.id.jrzkx_01);
TextView jrzkx_02
= (TextView)findViewById(R.id.jrzkx_02);
TextView jrzkx_03
= (TextView)findViewById(R.id.jrzkx_03);
TextView Zrzkx_0
= (TextView)findViewById(R.id.zrzkx_0);
TextView Zrzkx_01
= (TextView)findViewById(R.id.zrzkx_01);
TextView Zrzkx_02
= (TextView)findViewById(R.id.zrzkx_02);
TextView Zrzkx_03
= (TextView)findViewById(R.id.zrzkx_03);

Time t
= new Time();
t.setToNow();
int yesterday = t.monthDay - 1 ;
int lastmonth = t.month + 1 ;
String laststrday
= "";
laststrday
= t.year + "" + lastmonth + "" + yesterday +"";
final String str = t.year + "" + lastmonth + "" + t.monthDay + "";

if(nowtime.equals(str)==true)
{
vt_qdt.setText(
"日期:"+ nowtime +"已签到!");
bt_qiandao2.setBackgroundResource(R.drawable.yqd);
}
else
{
vt_qdt.setText(
"日期:"+ str);
bt_qiandao2.setBackgroundResource(R.drawable.qd);
}

//签到功能
bt_qiandao2.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
SharedPreferences my_rmb_data = getSharedPreferences(PublicDataCost.MY_RMBCost, 0);
if(my_rmb_data.getString(PublicDataCost.TodayTime, "").toString().equals(str)==true)
{
Toast.makeText( todayspend.
this , "今日已签到!", Toast.LENGTH_SHORT).show();
}
else
{
my_rmb_data.edit()
.putString(PublicDataCost.TodayTime, str)
.commit();
vt_qdt.setText(
"日期:"+ str +"已签到!");
bt_qiandao2.setBackgroundResource(R.drawable.yqd);
Toast.makeText( todayspend.
this , "签到成功!", Toast.LENGTH_SHORT).show();
onCreate(savedInstanceState);
}
}
});

final String[] AllFeild =
{
PublicDataCost.ID,
PublicDataCost.Field_1_1,
PublicDataCost.Field_1_2,
PublicDataCost.Field_1_3,
PublicDataCost.Field_1_4,
PublicDataCost.Field_1_5,
PublicDataCost.Field_1_6
};

//实例化增 事件
sqlc.dbl_add = new OnClickListener() {
public void onClick(View v) {
if(addflag == false)
{
//添加
Cursor c = db.query(PublicDataCost.Tb_Name_1, AllFeild, "DateTimes='" + str + "'", null, null, null, null);
if(c.getCount()>0)
{
Toast.makeText( todayspend.
this , "今天已经添加账单,你可以修改今日账单!", Toast.LENGTH_SHORT).show();
}
else
{
ContentValues cv
= new ContentValues();
cv.put( PublicDataCost.Field_1_1 , tv_Morning.getText().toString());
cv.put( PublicDataCost.Field_1_2 , tv_noon.getText().toString());
cv.put( PublicDataCost.Field_1_3 , tv_Night.getText().toString());
cv.put( PublicDataCost.Field_1_4 , tv_OtherSpend.getText().toString());
cv.put( PublicDataCost.Field_1_5 , tv_DailySpend.getText().toString());
cv.put( PublicDataCost.Field_1_6 , str);
SQLiteDatabase db
= sqlc.getReadableDatabase();
db.insert(PublicDataCost.Tb_Name_1,
null, cv);
db.close();
Toast.makeText( todayspend.
this , "添加成功!", Toast.LENGTH_SHORT).show();
onCreate(savedInstanceState);
}
c.close();
}
else
{
//修改
ContentValues cv = new ContentValues();
cv.put( PublicDataCost.Field_1_1 , tv_Morning.getText().toString());
cv.put( PublicDataCost.Field_1_2 , tv_noon.getText().toString());
cv.put( PublicDataCost.Field_1_3 , tv_Night.getText().toString());
cv.put( PublicDataCost.Field_1_4 , tv_OtherSpend.getText().toString());
cv.put( PublicDataCost.Field_1_5 , tv_DailySpend.getText().toString());
String sqlwhere
= PublicDataCost.ID + " = " + spinnerid;
SQLiteDatabase db
= sqlc.getReadableDatabase();
db.update(PublicDataCost.Tb_Name_1, cv, sqlwhere ,
null);
db.close();
onCreate(savedInstanceState);
Toast.makeText( todayspend.
this , "修改成功!", Toast.LENGTH_SHORT).show();

}
}
};
//将事件绑定到按钮
bt_addspend.setOnClickListener(sqlc.dbl_add);
//绑定列表
Cursor c = db.query( PublicDataCost.Tb_Name_1 , new String[] {PublicDataCost.Field_1_6}, null, null, null , null, null);
c.moveToFirst();
CharSequence[] cslist
= new CharSequence[c.getCount()];
for(int i=0;i<cslist.length;i++)
{
cslist[i]
=c.getString(0);
c.moveToNext();
}
c.close();
Spinner sp
= (Spinner)findViewById(R.id.spinner1);
sp.setAdapter(
new ArrayAdapter<CharSequence>(this,android.R.layout.simple_dropdown_item_1line,cslist));
sp.setSelection(cslist.length
-1);
//注册事件
sp.setOnItemSelectedListener(new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent ,View view, int position, long id){
String todaydatetime
= ((Spinner)parent).getSelectedItem().toString();
Cursor c
= db.query(PublicDataCost.Tb_Name_1, AllFeild, "DateTimes='" + todaydatetime + "'", null, PublicDataCost.Field_1_6, null, PublicDataCost.Field_1_6);
c.moveToFirst();
spinnerid
= Integer.parseInt(c.getString(0));
tv_Morning.setText(c.getString(
1));
tv_noon.setText(c.getString(
2));
tv_Night.setText(c.getString(
3));
tv_OtherSpend.setText(c.getString(
4));
tv_DailySpend.setText(c.getString(
5));
c.close();
}

public void onNothingSelected(AdapterView<?> arg0) {
// TODO Auto-generated method stub

}
});

//理财信息显示及处理
Cursor c2 = db.query( PublicDataCost.Tb_Name_1, AllFeild , "DateTimes='" + str + "'" , null, null, null, null);
c2.moveToFirst();
if(c2.getCount()>0)
{
int lastspend = Integer.parseInt(c2.getString(1))+Integer.parseInt(c2.getString(2))+Integer.parseInt(c2.getString(3))+Integer.parseInt(c2.getString(4))+Integer.parseInt(c2.getString(5));
jrzkx_01.setText(
"早:" + c2.getString(1) + " 中:"+ c2.getString(2)+" 晚:"+c2.getString(3));
jrzkx_02.setText(
"购置:"+ c2.getString(4)+" 日常:"+c2.getString(5));
jrzkx_03.setText(
"今日总消费金额:"+ lastspend);
bt_addspend.setText(
"修 改");
addflag
= true;
}
else{
jrzkx_0.setText(
"今日未记账");
jrzkx_01.setText(
"");
jrzkx_02.setText(
"");
jrzkx_03.setText(
"");
}
c2.close();

if(yesterday>0)
{
Cursor c3
= db.query( PublicDataCost.Tb_Name_1, AllFeild , "DateTimes='" + laststrday + "'" , null, null, null, null);
c3.moveToFirst();
if(c3.getCount()>0)
{
int lastspend = Integer.parseInt(c3.getString(1))+Integer.parseInt(c3.getString(2))+Integer.parseInt(c3.getString(3))+Integer.parseInt(c3.getString(4))+Integer.parseInt(c3.getString(5));
Zrzkx_01.setText(
"早:" + c3.getString(1) + " 中:"+ c3.getString(2)+" 晚:"+c3.getString(3));
Zrzkx_02.setText(
"购置:"+ c3.getString(4)+" 日常:"+c3.getString(5));
Zrzkx_03.setText(
"昨日总消费金额:"+ lastspend);
}
else{
Zrzkx_0.setText(
"昨日未记账");
Zrzkx_01.setText(
"");
Zrzkx_02.setText(
"");
Zrzkx_03.setText(
"");
}
c3.close();
}
else
{
Zrzkx_0.setText(
"昨日未记账");
Zrzkx_01.setText(
"");
Zrzkx_02.setText(
"");
Zrzkx_03.setText(
"");
}

}


}

代码写好了最后跑起来看一下效果:

Android应用之个人应用软件开发(3)【SQLite数据库及理财功能实现】

Android应用之个人应用软件开发(3)【SQLite数据库及理财功能实现】

Android应用之个人应用软件开发(3)【SQLite数据库及理财功能实现】

 哈哈,然后就可以一目了然的看到很清晰的理财数据,操作也方便,也达到了我们预期想要的功能(记录前一天的理财信息,一键添加,修改,进行理财查询和对比)。

 接下来就是做一个弹入弹出式菜单列表,来对这些功能进行详细的统一管理存放的栏目菜单。

 希望和大家多多相互学习更多的安卓开发方面的相关知识。

分类: 未分类 标签:

3ds max 中平滑组顶点法线的导出

2011年8月16日 没有评论

                3ds max中导出顶点的法线看似很容易,直接通过mesh->getNormal(i);可以获取,但实际上这样获取的法线不一定对。

实际在3ds max中会常常使用平滑组来对面法线进行指定。这样的结果是一个顶点可能处于多个平滑组中。或者说,一个顶点有N个法线对应。

所以,务必将这种情况修改为一个顶点与一个法线对应。

我的做法是:

           遍历每一个面中的三个顶点。取出法线,并将对应的法线放入对应顶点信息结构的法线容器中。如果已经有相同法线。则直接返回顶点信息结构的新增顶点索引容器中对应的索引做为面顶点索引。否则以新增顶点索引做为面顶点索引。

for(int v = 0 ; v < 3 ; v++)
{
GetVertexNormalUsingSmoothGroup(norm,*mesh,i,mesh->faces[i].v[v]);
norm = norm * NrmMat ;
norm.Normalize();
tFace.mNormal = norm;

                                                       SVertex*tpVertex = &(pMeshNode->m_SubMeshVec.back().m_VertexVec[mesh->faces[i].v[v]]);

if(true == tpVertex->mNormalVec.empty())
{
tpVertex->mNPosX = norm.x ;
tpVertex->mNPosY = norm.z ;
tpVertex->mNPosZ = norm.y ;

tpVertex->mNormalVec.push_back(norm);
tpVertex->mVertexVec.push_back(mesh->faces[i].v[v]);
}
else
{

//法线VEC
vector<Point3>::iterator Iter;
bool tFind = false;
int tVertexIndex = 0;
for(Iter = tpVertex->mNormalVec.begin() ; Iter != tpVertex->mNormalVec.end(); Iter++)
{
if(norm == (*Iter))
{
tFind = true;

if(0 == v)
{
tFace.mVertexIndex1 = tpVertex->mVertexVec[tVertexIndex];
}
else if(1 == v)
{
tFace.mVertexIndex2 = tpVertex->mVertexVec[tVertexIndex];
}
else if(2 == v)
{
tFace.mVertexIndex3 = tpVertex->mVertexVec[tVertexIndex];
}
break;
}
tVertexIndex++;
}
if(false == tFind)
{
tpVertex->mNormalVec.push_back(norm);

SVertex
tNewVertex = *tpVertex;
tNewVertex.mNPosX = norm.x ;
tNewVertex.mNPosY = norm.z ;
tNewVertex.mNPosZ = norm.y ;

int tVertexIndex = pMeshNode->m_SubMeshVec.back().m_VertexVec.size();
tpVertex->mVertexVec.push_back(tVertexIndex);
pMeshNode->m_SubMeshVec.back().m_VertexVec.push_back(tNewVertex);

if(0 == v)
{
tFace.mVertexIndex1 = tVertexIndex ;
}
else if(1 == v)
{
tFace.mVertexIndex2 = tVertexIndex ;
}
else if(2 == v)
{
tFace.mVertexIndex3 = tVertexIndex ;
}

}
}

GetVertexNormalUsingSmoothGroup函数:

GetVertexNormalUsingSmoothGroup(Point3& VN, Mesh& mesh, int faceId, int vertexId) 

   // get the "rendered" vertex 
   RVertex *pRVertex = mesh.getRVertPtr(vertexId); 

   // get the face 
   const Face& Face = mesh.faces[faceId]; 

   // get the smoothing group of the face 
   const DWORD smGroup = Face.smGroup; 

   // get the number of normals 
   const int normalCount = pRVertex->rFlags & NORCT_MASK; 

   // check if the normal is specified … 
   if(pRVertex->rFlags & SPECIFIED_NORMAL) 
   { 
      VN = pRVertex->rn.getNormal(); 
      return; 
   } 
   // … otherwise, check for a smoothing group 
   else if((normalCount > 0) && (smGroup != 0)) 
   { 
      // If there is only one vertex is found in the rn member. 
      if(normalCount == 1) 
      { 
         VN = pRVertex->rn.getNormal(); 
         return; 
      } 
      else 
      { 
         for(int normalId = 0; normalId < normalCount; normalId++) 
         { 
            if(pRVertex->ern[normalId].getSmGroup() & smGroup) 
            { 
               VN = pRVertex->ern[normalId].getNormal(); 
               return; 
            } 
         } 
      } 
   } 

   // if all failed, return the face normal 
   VN = mesh.getFaceNormal(faceId); 

  
这样才可跟据平滑组导出直实的顶点法线~

分类: 未分类 标签:

Android应用之个人应用软件开发(2)【签到功能和记账】

2011年8月16日 没有评论

最近白天都有点忙,明天还要上班,恼火啊···现在才有空把这两篇文章发出来···

上次说了一个思路,那首先就是把UI弄出来。

android给我们提供了几种数据存储的方法:

1,Shared Preferences 2,sqlite database

利用SharedPreference来做一些简单的小功能还是很不错的。

下面我们来实现一个签到的功能。

如图:

Android应用之个人应用软件开发(2)【签到功能和记账】

      先来看看签到功能:

      主要就是进入理财界面有个类似提示今日是否进行过操作的记录,主要目的就是提醒是否今天已经进行过添加记账,而且在界面UI上面多弄这样一个简单的小功能也是很好看很不错的。呵呵,做了两张小图,一个是“签到” 一个是“未签到” 那接下来就看看代码怎么写的。

     首先定义一下共享优先数据基础字段:

    

     //定义共享优先数据及基础字段
private String MY_RMBCost ="MY_RMBCost";

private String TodayTime ="TodayTime";

     然后就是处理签到的功能:

Time t = new Time();
t.setToNow();
int lastmonth = t.month + 1 ;
final String str = t.year + "" + lastmonth + "" + t.monthDay + "";


final String nowtime =my_rmb_data.getString(TodayTime, "").toString();

if(nowtime.equals(str)==true)
{
tv_time.setText(
"日期:"+ nowtime +"已签到!");
bt_qiandao.setBackgroundResource(R.drawable.yqd);
}
else
{
tv_time.setText(
"日期:"+ str);
bt_qiandao.setBackgroundResource(R.drawable.qd);
}

页面的全部代码:

import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.text.format.Time;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class myrmbmanage extends Activity {

//定义共享优先数据及基础字段
private String MY_RMBCost ="MY_RMBCost";

private String TodayTime ="TodayTime";

public void onCreate(Bundle savedInstanceState ){
super.onCreate(savedInstanceState);
setContentView(R.layout.myrmbmanage);
final Button bt_qiandao = (Button)findViewById(R.id.bt_qiandao);
final TextView tv_time = (TextView)findViewById(R.id.tv_qiandaotime);
final Button bt_jz = (Button)findViewById(R.id.bt_jz);

//读取共享数据
SharedPreferences my_rmb_data = getSharedPreferences(MY_RMBCost, 0);

Time t
= new Time();
t.setToNow();
int lastmonth = t.month + 1 ;
final String str = t.year + "" + lastmonth + "" + t.monthDay + "";


final String nowtime =my_rmb_data.getString(TodayTime, "").toString();

if(nowtime.equals(str)==true)
{
tv_time.setText(
"日期:"+ nowtime +"已签到!");
bt_qiandao.setBackgroundResource(R.drawable.yqd);
}
else
{
tv_time.setText(
"日期:"+ str);
bt_qiandao.setBackgroundResource(R.drawable.qd);
}

//按钮操作部分

//签到功能
bt_qiandao.setOnClickListener(new OnClickListener() {

public void onClick(View v) {
// TODO Auto-generated method stub
SharedPreferences my_rmb_data = getSharedPreferences(MY_RMBCost, 0);
if(my_rmb_data.getString(TodayTime, "").toString().equals(str)==true)
{
Toast.makeText( myrmbmanage.
this , "今日已签到!", Toast.LENGTH_SHORT).show();
}
else
{
my_rmb_data.edit()
.putString(TodayTime, str)
.commit();
tv_time.setText(
"日期:"+ str +"已签到!");
bt_qiandao.setBackgroundResource(R.drawable.yqd);
Toast.makeText( myrmbmanage.
this , "签到成功!", Toast.LENGTH_SHORT).show();
}
}
});

//记账
bt_jz.setOnClickListener(new OnClickListener() {

public void onClick(View v) {
// TODO Auto-generated method stub
Intent intent = new Intent( myrmbmanage.this, todayspend.class);
startActivity(intent);
}
});

}
}

  签到功能只用到了 SharedPreferences ,而且如果我们拥有的是大量的数据,并且要随掉随用的方法那就得用到Sqlite database了。下一节说一下把这些和数据相关的东西分层,毕竟一个规整干净的代码才是我们想见到的。

  然后再来看一下记账功能的UI:

Android应用之个人应用软件开发(2)【签到功能和记账】

   上半部分同样继承了签到功能,还有把详细需要填写开销表单列出来了。简单易用就是我们想要的功能,我只想在以后我想记账的时候达到一键添加就可以纪录我今天的理财记账。下半部分主要显示了今日和昨日的开销信息,这样也有一个对比,昨天和今天的开资就一目了然了,哈哈。最重要的是下拉列表,有一个很重要的功能就是我们需要下拉列表显示这个月已经添加账目的日期,并且选中之后赋值到表单中可以进行修改编辑。也达到了查询任意一天的账目开销情况。那么我们整个UI就基本具有了这样预期的功能了。下一节我们就来实现这个功能。

  关于Sqlite database数据访问的东西下一节贴出来,也希望大家相互交流,如果有能改进的地方大家相互学习。

分类: 未分类 标签:

Android应用之个人应用软件开发(1)【需求及UI布局】

2011年8月13日 没有评论

需求:【理财+日志】

      

目前我个人做的是自己的一个理财软件,我这个人是一个极度木有理财观念的人,每个月没有固定的开资计划和理财计划。于是乎我看了别的理财软件也让我觉得很
繁琐和复杂我觉得如果让我来做一个理财软件,那第一必须得方便,个性化,有可能我一键就能记录我当天的开资情况(根据前一天的理财记录来添加第二天的理财
纪录是否一样)。而且是否每天都要统计开资呢,不一定,我只纪录我当天的花费即可,而且我可以编辑这个月内我某一天的开资情况,还有一个功能就是我忘了昨
天的理财添加了,我选择日期来进行理财管理。达到即使忘记了我也能添加回来。当然作为一个管理软件我们没有必要记得非常之精确,我们不是科学家要进行精确
的数值统计,我们只记录当月大概开资情况和,按照这个计划这个月的开资的花费那一部分超出了我们预期的开资。比如我早上买了10个包子,包子的价钱1元,
中午吃了20个包子,晚上吃了20个包子(当然我不是一直吃包子),我们就可以大致模糊理财。早餐10元,午餐20,晚餐20,是否有购买物品情况,必须
生活消耗品开资(菜米油盐酱醋茶等等)。好了不扣水勒。我直接把我需要的分为4大块!

       根据以上需求理财功能分为4大块:

       1,今日记账(纪录每一天的生活开资情况) 

       2,本月日历(这个月的日历分布)

       3,本月流水(本月开资消耗点柱状图)

       4,开资统计(一个月的预计开资 和 软件纪录的实际开资 比对情况)

       有了这4个功能那么我就可以看出我这个月的钱都花到哪去了,下个月应该怎么来理财,心里有个数就行,软件是死的,人是活的,我们还得每天按照自己的思想来活,活出精彩的每一天,哇哈哈。

UI设计:

      
UI设计,我们提到过Android Layout Edior 布局资源管理器。根据GOOGLE提供的人机接口我们可以方便的引用一些套件
Widget 这个非常成熟的套件,我觉得大致和silverlight / flax 等里面的控件大致一样的 ,还汤不换药  一个按钮是就是按钮 
它有事件 给我们提供服务 . 

       首先我们新建一个工程,可以看到工程建立起来后已经给我们自动配置和引入了安卓开发必备的环境。

Android应用之个人应用软件开发(1)【需求及UI布局】

       当然我们也看到了androidManifest.xml配置文件。我们的程序的程序的入口点是main.xml ,那我们就来设计一下我们的界面吧.

       由于我想以后拓展成为公用软件,那我就要设计一个登陆页面,但这个页面暂时没有数据功能。但依然能达到我们登陆的效果,设计思路当然和传统的一样。设计之前简单介绍一下android有哪几种布局方式:

       不同的布局根据不同的屏幕适应性也是很重要的。android屏幕常用的有3种屏幕尺寸,这里我也就说一种160的。

       desity=160 分辨率:320px * 533px 平均是3个点两个分辨率  状态栏 25px 25px  竖屏 320px * 508px

       1,表格布局 tablelayout(自适应度中,和web里面的tabel一样的 行 和 列必须是对齐的)

       2 , 线性布局 linearlayout(以行为线布局,自适应高)

       3 , 相对布局 Relativelayout(根据margin属性进行相对布局,适应度也是比较高的)

       4 , 绝对布局 absolutelayout(根据直接定义绝对路径坐标来设置 ,layout_x/y 来适应屏幕尺寸)

       5 , 框架布局 Framelayout

      
再来说一下drawable-*的3个目录是干什么用的,存放了3中不同图标的文件, hdpi:72*72 ; mdpi:48*48 ;
ldpi:36 *36
这些尺寸自己设置好,在路径中对于的图片大小也是不一样的,比如我们在任务栏看到的,和在应用版面上看到的是不同尺寸的道理是一样的。

       接下来就是设计UI我了2中方式(linearlayout , absolutelayout)实现了如图所示的布局:

       具体实现大家参考代码吧

       有两个窗体 一个是Mian.xml 另一个是 mylist.xml

      

Android应用之个人应用软件开发(1)【需求及UI布局】

Android应用之个人应用软件开发(1)【需求及UI布局】

      界面设计好了,接下来是做登陆的代码了,在建立项目的时候选项:Create Activty 入口点Activityclass名 。我们看一下androidManifest.xml里面的具体内容

Android应用之个人应用软件开发(1)【需求及UI布局】

      在ZisousoftminiActivity里面书写代码内容:

      全文代码:

     

package Zisou.Soft.mini;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class ZisousoftminiActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//调用main.xml layout窗体
setContentView(R.layout.main);
//目前就不用用户名和密码 等待以后拓展SQLite数据
final String str_username = "";
final String str_pwd = "";
//控件定义方法findViewById
final EditText Et_username = (EditText)findViewById(R.id.editText1);
final EditText Et_pwd = (EditText)findViewById(R.id.editText2);

Button bt_login
= (Button)findViewById(R.id.button1);
//通过setOnClickListener来监听并注册OnClickListener时间方法
bt_login.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
if(str_username.equals(Et_username.getText().toString().trim())==true)
{
if(str_pwd.equals(Et_pwd.getText().toString().trim())==true)
{
final ProgressDialog progressDialog = ProgressDialog.show(ZisousoftminiActivity.this, "登陆中...", "请稍等,正在登陆...");
final Handler handler = new Handler();

final Runnable callback = new Runnable() {
public void run() {
//回调处理
progressDialog.dismiss();//关闭对话窗口
Intent intent = new Intent(ZisousoftminiActivity.this, mylist.class);//利用Intent创建一个窗口活动程序的动作
startActivity(intent);//切换该窗口mylist
}
};
//声明一个线程并处理回调
Thread thread = new Thread() {
@Override
public void run() {
try {
Thread.sleep(
5000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
handler.post(callback);
}
};
thread.start();
}
else
{
Toast.makeText( ZisousoftminiActivity.
this , "密码有误", Toast.LENGTH_SHORT).show();
}
}
else
{
Toast.makeText( ZisousoftminiActivity.
this , "用户名错误", Toast.LENGTH_SHORT).show();
}
}
});

}
}

            代码中我们看到了这样一段 setContentView(R.layout.main);
打开程序入口点的Activity窗体 ,
通过setOnClickListener来监听并注册OnClickListener时间方法,使我们能书写点击按钮之后的具体方法。其中声明了
ProgressDialog类 会话窗口类 android SDK给我提供了5种类型,PopupWindosw 、Dialog
、AlertDialog 、ProgressDialog 、Toast 等我们用到了两种。

            ProgressDialog的使用方法:

final ProgressDialog progressDialog = ProgressDialog.show(ZisousoftminiActivity.this, "登陆中...", "请稍等,正在登陆...");
final Handler handler = new Handler();

final Runnable callback = new Runnable() {
public void run() {
progressDialog.dismiss();
Intent intent
= new Intent(ZisousoftminiActivity.this, mylist.class);
startActivity(intent);
}
};

Thread thread
= new Thread() {
@Override
public void run() {
try {
Thread.sleep(
5000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
handler.post(callback);
}
};
thread.start();

             Toast 的使用方法:

             要注意的是 ZisousoftminiActivity.this 指在当前的Activity中进行切换

Toast.makeText( ZisousoftminiActivity.this , "提示内容", Toast.LENGTH_SHORT).show();

             Intent是android Activity中重要的一个控制类 ,一个是对Action 的处理 一个是对 data to act on 的处理。

             在ZisousoftminiActivity里面书写代码内容:

package Zisou.Soft.mini;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.AdapterView.OnItemClickListener;

public class mylist extends Activity {

private Object[] actobj={
"个人理财管理", myrmbmanage.class,
"个人日志", myrizi.class,
};

public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mylist);

//创建数组
CharSequence[] list = new CharSequence[actobj.length/2];
//序列化list
for(int i = 0 ; i <list.length; i++)
{
list[i]
=(String)actobj[i*2];
}
//BindListView提取数组出来绑定Text内容值
ArrayAdapter<CharSequence> adp = new ArrayAdapter<CharSequence>(mylist.this, android.R.layout.simple_list_item_1 ,list);
ListView lv
= (ListView)findViewById(R.id.ListView01);
lv.setAdapter(adp);
//setOnItemClickListener为每一个Itme设置OnItemClickListener事件
lv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//创建List动作
Intent intent = new Intent(mylist.this, (Class<?>)actobj[position * 2 + 1]);
startActivity(intent);
}
});
}
}

             程序写完了跑一下看看是不是我们想要的功能:

            

Android应用之个人应用软件开发(1)【需求及UI布局】

    

Android应用之个人应用软件开发(1)【需求及UI布局】

         嗯,看来大体的UI设计工作已经到位了。感觉还是很不错的,下一部分我将会继续努力,写接下来的个人理财管理里面的UI,和功能说明!

         希望和大家一起学习安卓开发和相关应用开发。后面会我会用到一个设计模式来写这个程序。主要是用于数据库访问类库方面的。

      

分类: 未分类 标签:

Android应用之个人应用软件开发【android环境搭建及说明】

2011年8月13日 没有评论

 安卓系统的环境搭建

 1,Android环境都包括哪些内容?

   Android SDK (Software Developemt kit) SDK
,它包括android操作系统,仿真器,Eclipse集成环境、及android开发工具ADT.

 2,必备需要安装的软件?

   安卓系统是基于JAVA开发的,所以必须安装Eclipse集成环境.

   Android SDK 地址:http://developer.android.com/sdk/

   按照最新的安卓SDK下载,校验码就不说了.当然安装好要进行配置环境变量,方便以后使用。

   在SDK Tools目录设置到自己的path路径

   Android ADT 是集成在Ecilpse里面,help里面配置-install new
software 加入更新字段URL来进行ADT的下载安装

   地址是:http://dl-ssl.google.com/android/eclipse/ 
下载更新比较慢,大家需要有足够耐性,这可不比微软的那一套都给你准备好了

  
下载更新完毕后可以看到界面中已经有了android的相关操作按钮,然后在配置好android环境SDK目录Preferences里面设置环境.

 安卓系统简要说明

   博客园写的详细的文章太多了,我就不在这里口水了,小弟也是在以前的sl,和flax的基础经验上来做这个应用的。

   首先我们了解一下安装的应用程序组成

   分为活动程序Activity , 服务程序Service , 广播接收器Broadcast Reciver ,
内容提供器Content Prodvider   

   我们所做的,看到的安卓应用程序都是由Activity组成,你可以把Activity理解为窗体,视图的表现层。

   Activity为载体的单元中我们的部件也有继承关系:如 TextView -> View -> Object 。

   安卓还分为重要的开发要素步骤:

   AndroidManifest  信息配置文件 配置文件(配置基本的packgae、activity 、及应用程序执行进入点)

   res/layout 窗体布局文件 – 布局编辑器

   velues 资源文件 – 资源编辑器 – 配置好资源文件可以方便以后做好国际化。

   首先要进行窗口的创建、UI的设计布局、资源文件的添加、以及JAVA功能需求的代码编写、以及AndroidManifest  的配置设置。

   最后编译完成没有错误之后,就是通过我们的模拟器来进行调试了。

分类: 未分类 标签:

Game engines for IPhone game development

2011年8月3日 没有评论

I am totally new to IPhone game development enviornment. Kindly suggest me with some common game engines used for developing games on IPhone.

Jimmy

Check out:

cocos2d

In my opinion by far the best iphone framework for game development, easy, fast, flexible and well documented.

http://www.anscamobile.com/corona/

Unity 3D offers a free trial for their iPhone pro publishing service. Of course, that would assume you’re familiar with the platform and have already built a game using that engine. The benefit would be having the ability to use more open-source languages like JavaScript, and C# if you’re already familiar with .NET.

I know a lot of game companies are starting to hire Unity developers too. So, if you’re looking to work in the industry, outside of personal projects, becoming proficient in Unity 3D may not be a bad idea…

Corona SDK & Unity 3D

Follow below 2 links to learn more about them

http://click-labs.com/mobile/mobile-application-development/mobile-game-development/2d-game-development-in-corona-sdk/

http://click-labs.com/mobile/mobile-application-development/mobile-game-development/mobile-game-development-in-unity-3d/

分类: stackoverflow精选, unity3d 标签: