[转载]helloPe的android项目实战之连连看—实现篇(三)

mikel阅读(1045)

[转载]helloPe的android项目实战之连连看—实现篇(三) – HelloPe – 博客园.

前面两篇“实现篇”已经将程序后台框架基本实现了,今天将涉及程序的activity类,在这个类中,为了有一个比较好的视觉效果,将介绍一些 Android中动画效果,依靠animation来实现,以及简单介绍Android中自定义dialog的实现;首先看一下游戏界面运行时的效果图 (程序中图片使用了网上的网友的,仅当学习之用):

游戏运行时界面                                              用于显示游戏结果的自定义dialog显示

先看看用于显示程序的activity类中的代码(这里主要是一些调用等,实现的逻辑在前面两篇文章中已经包含了)

package nate.llk;

//包得导入略去

public class GameActivity extends Activity implements OnToolsChangeListener,OnTimerListener,
						OnStateListener{
	private ImageButton img_startPlay;
	private ImageView img_title;
	private ProgressBar progress;
	
	private MyDialog dialog;
	//visibility at first is "gone"
	private ImageView clock;
	private GameView gameView = null;
	private ImageButton img_tip;
	private ImageButton img_refresh;
	private TextView text_refreshNum;
	private TextView text_tipNum;
	//两个帮助按键的特效
	private Animation anim = null;

	
	private Handler handler = new Handler(){
		@Override
		public void handleMessage(Message msg) {
			switch(msg.what){
			case 0:
				dialog = new MyDialog(GameActivity.this,gameView,"完成!",gameView.getTotalTime() - progress.getProgress() + 1);
				dialog.show();
				break;
			case 1:
				dialog = new MyDialog(GameActivity.this,gameView,"失败!",gameView.getTotalTime() - progress.getProgress() + 1);
				dialog.show();
			}
		}
	};
	
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.game_view);
        anim =  AnimationUtils.loadAnimation(this, R.anim.shake);
        findView();
        startView();
        
        img_startPlay.setOnClickListener(new BtnClickListener());
       
        gameView.setOnTimerListener(this);
        gameView.setOnStateChangeListener(this);
        gameView.setOnToolsChangedListener(this);
        img_refresh.setOnClickListener(new BtnClickListener());
        img_tip.setOnClickListener(new BtnClickListener());
    }//end of the OnCreate method!
    /**
     * 寻找对应资源控件
     */
    public void findView(){
    	clock = (ImageView)this.findViewById(R.id.clock);
    	progress = (ProgressBar)this.findViewById(R.id.timer);
    	img_title = (ImageView)this.findViewById(R.id.title_img);
    	img_startPlay = (ImageButton)this.findViewById(R.id.play_btn);
    	img_tip = (ImageButton)this.findViewById(R.id.tip_btn);
    	img_refresh = (ImageButton)this.findViewById(R.id.refresh_btn);
    	gameView = (GameView)this.findViewById(R.id.game_view);
    	text_refreshNum = (TextView)this.findViewById(R.id.text_refresh_num);
    	text_tipNum = (TextView)this.findViewById(R.id.text_tip_num);
    }
    /**
     * 程序开启界面显示
     */
    public void startView(){
    	Animation scale = AnimationUtils.loadAnimation(this,R.anim.scale_anim);
    	img_title.startAnimation(scale);
    	img_startPlay.startAnimation(scale);
    }
    /**
     * 游戏运行时界面显示,即连连看的布局
     */
    public void playingView(){
    	Animation scaleOut = AnimationUtils.loadAnimation(this, R.anim.scale_anim_out);
    	img_title.startAnimation(scaleOut);
    	img_startPlay.startAnimation(scaleOut);
    	img_title.setVisibility(View.GONE);
    	img_startPlay.setVisibility(View.GONE);
    	
    	clock.setVisibility(View.VISIBLE);
    	progress.setMax(gameView.getTotalTime());
    	progress.setProgress(gameView.getTotalTime());
    	progress.setVisibility(View.VISIBLE);
    	gameView.setVisibility(View.VISIBLE);
    	img_tip.setVisibility(View.VISIBLE);
    	img_refresh.setVisibility(View.VISIBLE);
    	text_tipNum.setVisibility(View.VISIBLE);
    	text_refreshNum.setVisibility(View.VISIBLE);
    	Animation animIn = AnimationUtils.loadAnimation(this, R.anim.trans_in);
    	gameView.startAnimation(animIn);
    	img_tip.startAnimation(animIn);
    	img_refresh.startAnimation(animIn);
    	text_tipNum.startAnimation(animIn);
    	text_refreshNum.startAnimation(animIn);
    	//player.pause();
		gameView.startPlay();
		toast();
    }
    /**
     * 一个处理开始游戏,刷新,帮助三个按钮的listener的类
     * @author HelloPe || NatePan
     *
     */
    class BtnClickListener implements OnClickListener{
		@Override
		public void onClick(View v) {
			switch(v.getId()){
			case R.id.play_btn:
				playingView();
				break;
			case R.id.refresh_btn:
				img_refresh.startAnimation(anim);
				gameView.refreshChange();
				gameView.invalidate();
				break;
			case R.id.tip_btn:
				img_tip.startAnimation(anim);
				gameView.autoHelp();
				break;
			}
		}
    }
	@Override
	public void onRefreshChanged(int count) {
		text_refreshNum.setText(""+gameView.getRefreshNum());
	}
	@Override
	public void onTipChanged(int count) {
		text_tipNum.setText("" + gameView.getTipNum());
	}
	@Override
	public void onTimer(int leftTime) {
		progress.setProgress(leftTime);
		
	}
	
	/**
	 *用来控制音乐的播放 
	 */
	@Override
	public void OnStateChanged(int StateMode) {
		switch(StateMode){
		case GameView.WIN:
			handler.sendEmptyMessage(0);
			break;
		case GameView.LOSE:
			handler.sendEmptyMessage(1);
			break;
		case GameView.PAUSE:
			//player.stop();
	    	//gameView.player.stop();
	    	gameView.stopTimer();
			break;
		case GameView.QUIT:
			//player.release();
	    	//gameView.player.release();
	    	gameView.stopTimer();
	    	break;
		}
	}
	public void quit(){
		this.finish();
	}
	/**
	 * 用于提醒游戏开始,提醒总时间
	 */
	public void toast(){
		Toast.makeText(this, "游戏已经开始!总时间: " + gameView.getTotalTime() + "s", Toast.LENGTH_LONG).show();
	}
	 	@Override
	    protected void onPause() {
	    	super.onPause();
	    	gameView.setMode(GameView.PAUSE);
	    }   
	    @Override
		protected void onDestroy() {
	    	super.onDestroy();
	    	gameView.setMode(GameView.QUIT);
		}
		@Override
		public boolean onCreateOptionsMenu(Menu menu) {
			menu.add(Menu.NONE, 1, Menu.NONE,"Replay").setIcon(R.drawable.buttons_replay);
			menu.add(Menu.NONE, 2, Menu.NONE, "Pause").setIcon(R.drawable.pause);
			menu.add(Menu.NONE, 3, Menu.NONE,"SoundOn").setIcon(R.drawable.volume);
			return super.onCreateOptionsMenu(menu);
		}
		@Override
		public boolean onOptionsItemSelected(MenuItem item) {
			switch(item.getItemId()){
			case 1:
				gameView.setTotalTime(100);
				progress.setMax(100);
				gameView.startPlay();
				break;
			case 2:
				gameView.stopTimer();
				if(item.getTitle().equals("Pause")){
					item.setTitle("Continue");
					item.setIcon(R.drawable.play);
				}else if(item.getTitle().equals("Continue")){
					item.setTitle("Pause");
					item.setIcon(R.drawable.pause);
				}
				AlertDialog.Builder dialog = new AlertDialog.Builder(this);
				dialog.setIcon(R.drawable.icon);
				dialog.setTitle("继续");
				dialog.setMessage("继续游戏?");
				dialog.setPositiveButton("继续", new DialogInterface.OnClickListener() {
					
					@Override
					public void onClick(DialogInterface dialog, int which) {
						gameView.setContinue();
					}
				}).setNeutralButton("重玩", new DialogInterface.OnClickListener() {
					
					@Override
					public void onClick(DialogInterface dialog, int which) {
						gameView.startPlay();
					}
				}).setNegativeButton("退出", new DialogInterface.OnClickListener() {
					
					@Override
					public void onClick(DialogInterface dialog, int which) {
						Intent startMain = new Intent(Intent.ACTION_MAIN);  
	                    startMain.addCategory(Intent.CATEGORY_HOME);   
	                    startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);   
	                    startActivity(startMain);  
	                    System.exit(0); 
					}
				});
				dialog.show();
				break;
			case 3:
				///////////////////////////
				if(item.getTitle().equals("Mute")){
					item.setTitle("SoundOn");
					item.setIcon(R.drawable.volume);
				}else if(item.getTitle().equals("SoundOn")){
					item.setTitle("Mute");
					item.setIcon(R.drawable.mute);
				}
				break;
			}
			return super.onOptionsItemSelected(item);
		}
		/**
		 * 监听后退按钮,以防止误按,按下back按钮后,程序应当处于暂停状态
		 */
		@Override
		public boolean onKeyDown(int keyCode, KeyEvent event) {
			if(keyCode == KeyEvent.KEYCODE_BACK){
				AlertDialog.Builder dialog= new AlertDialog.Builder(GameActivity.this).setTitle("退出游戏")
				.setMessage("确定退出游戏?")
				.setPositiveButton("是",new DialogInterface.OnClickListener(){

					@Override
					public void onClick(DialogInterface dialog, int which) {
						Intent startMain = new Intent(Intent.ACTION_MAIN);  
	                    startMain.addCategory(Intent.CATEGORY_HOME);   
	                    startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);   
	                    startActivity(startMain);  
	                    System.exit(0); 
					}
				}).setNegativeButton("否", new DialogInterface.OnClickListener(){

					@Override
					public void onClick(DialogInterface dialog, int which) {
						Toast.makeText(GameActivity.this, "重新开始了游戏", Toast.LENGTH_LONG).show();
						gameView.startPlay();
					}
					
				});
				dialog.setIcon(R.drawable.icon);
				dialog.show();
			}
			return super.onKeyDown(keyCode, event);
		}
	    
}

在此类中,如上次我们所说的,我们实现了之前定义的三个接口,引用了GameView类(在activity的布局文件中使用到),在activity布局文件中如下使用:

<nate.llk.view.GameView
  	android:layout_width="wrap_content" 
  	android:layout_height="wrap_content" 
  	android:id="@+id/game_view"
  	android:visibility="gone"
  	android:layout_below="@id/timer"
  />

同样对于我们自定义的dialog,跟自定义的GameView(继承自View)是一样的。MyDialog类继承自Dialog类,实现了OnClickListener的OnClick方法,使用一个布局文件,将自定义的dialog布局。布局文件很简单,MyDialog类如下:

public class MyDialog extends Dialog implements OnClickListener{

	private GameView gameview;
	private Context context;
	
	public MyDialog(Context context, GameView gameview, String msg, int time) {
		super(context,R.style.dialog);
		this.gameview = gameview;
		this.context = context;
		this.setContentView(R.layout.dialog_view);
		TextView text_msg = (TextView) findViewById(R.id.text_message);
		TextView text_time = (TextView) findViewById(R.id.text_time);
		ImageButton btn_menu = (ImageButton) findViewById(R.id.menu_imgbtn);
		ImageButton btn_next = (ImageButton) findViewById(R.id.next_imgbtn);
		ImageButton btn_replay = (ImageButton) findViewById(R.id.replay_imgbtn);
		
		text_msg.setText(msg);
		text_time.setText(text_time.getText().toString().replace("$", String.valueOf(time)));
		btn_menu.setOnClickListener(this);
		btn_next.setOnClickListener(this);
		btn_replay.setOnClickListener(this);
		this.setCancelable(false);
	}

	@Override
	public void onClick(View v) {
		this.dismiss();
		switch(v.getId()){
		case R.id.menu_imgbtn:
			Dialog dialog = new AlertDialog.Builder(context)
            .setIcon(R.drawable.buttons_bg20)
            .setTitle(R.string.quit)
            .setMessage(R.string.sure_quit)
            .setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int whichButton) {
                	((GameActivity)context).quit();
                }
            })
            .setNegativeButton(R.string.alert_dialog_cancel, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int whichButton) {
                	gameview.startPlay();
                }
            })
            .create();
			dialog.show();
			break;
		case R.id.replay_imgbtn:
			gameview.startPlay();
			break;
		case R.id.next_imgbtn:
			gameview.startNextPlay();
			break;
		}
	}

	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		if(keyCode == KeyEvent.KEYCODE_BACK){
			this.dismiss();
		}
		return super.onKeyDown(keyCode, event);
	}
	
}

上面代码简单,不过还是实现了较好的效果。

在android中使用animation的动画包含四种,Tween animation的使用也能够使程序看起来效果好点:

在anim文件下:

实现当点击程序中两个工具按钮时,工具按钮出现抖动的效果:

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android" 
			android:fromXDelta="0" 
			android:toXDelta="10" 
			android:duration="1000" 
			android:interpolator="@anim/cycle" />

用于控制欢迎界面的图标逐渐变大的出场效果:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
	<scale
          android:interpolator="@android:anim/accelerate_decelerate_interpolator"
          android:fromXScale="0.0"
          android:toXScale="1.0"
          android:fromYScale="0.0"
          android:toYScale="1.0"
          android:pivotX="50%"
          android:pivotY="50%"
          android:fillAfter="true"
          android:duration="1600" />
</set>

当然放大效果只是改一下android:fromXScale=”1.0″ 与 android:toXScale=”0.0″即可;

至于透明效果,用于将GameView中的内容从透明慢慢展示出来:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
	<alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="1000" />
</set>

而在activity中对于以上资源的使用上面activity类中已经给出,先载入,然后调用imageView或者其他View的startAnimation方法即可;

对于游戏中音效的播放方法比较简单,主要是在不同的状态播放不同的声音比较繁琐,android中有两种播放音效的方法:一种是SoundPool,一种是MediaPlayer。SoundPool适合短促音乐,但是反应速度要求比较高的情况;MediaPlayer则是是相反。使用步骤如:

// 初始化soundPool 对象,第一个参数是允许有多少个声音流同时播放,第2个参数是声音类型,第三个参数是声音的品质
		soundPool = new SoundPool(25, AudioManager.STREAM_MUSIC, 100);//SoudPool的引用
soundPool.load(context, raw, 1);//调用load函数载入音乐资源
//之后调用play函数即可播放参数中相应的音乐资源

本程序算是完成了,向网友们学习了不少,毕竟是很多人都做过的小项目。记录下来,希望高手路过别喷~

[转载]股票API

mikel阅读(1305)

[转载]股票API – 狼の禅 – 博客园.

股票数据的获取目前有如下两种方法可以获取:
1. http/JavaScript接口取数据
2. web-service接口

1.http/JavaScript接口取数据

1.1Sina股票数据接口

以大秦铁路(股票代码:601006)为例,如果要获取它的最新行情,只需访问新浪的股票数据
接口:

http://hq.sinajs.cn/list=sh601006

这个url会返回一串文本,例如:

var hq_str_sh601006=”大秦铁路, 27.55, 27.25, 26.91, 27.55, 26.20, 26.91, 26.92, 
22114263, 589824680, 4695, 26.91, 57590, 26.90, 14700, 26.89, 14300,
26.88, 15100, 26.87, 3100, 26.92, 8900, 26.93, 14230, 26.94, 25150, 26.95, 15220, 26.96, 2008-01-11, 15:05:32″;

这个字符串由许多数据拼接在一起,不同含义的数据用逗号隔开了,按照程序员的思路,顺序号从0开始。

0:”大秦铁路”,股票名字;
1:”27.55″,今日开盘价;
2:”27.25″,昨日收盘价;
3:”26.91″,当前价格;
4:”27.55″,今日最高价;
5:”26.20″,今日最低价;
6:”26.91″,竞买价,即“买一”报价;
7:”26.92″,竞卖价,即“卖一”报价;
8:”22114263″,成交的股票数,由于股票交易以一百股为基本单位,所以在使用时,通常把该值除以一百;
9:”589824680″,成交金额,单位为“元”,为了一目了然,通常以“万元”为成交金额的单位,所以通常把该值除以一万;
10:”4695″,“买一”申请4695股,即47手;
11:”26.91″,“买一”报价;
12:”57590″,“买二”
13:”26.90″,“买二”
14:”14700″,“买三”
15:”26.89″,“买三”
16:”14300″,“买四”
17:”26.88″,“买四”
18:”15100″,“买五”
19:”26.87″,“买五”
20:”3100″,“卖一”申报3100股,即31手;
21:”26.92″,“卖一”报价
(22, 23), (24, 25), (26,27), (28, 29)分别为“卖二”至“卖四的情况”
30:”2008-01-11″,日期;
31:”15:05:32″,时间;

一个简单的JavaScript应用例子:

<script type=text/javascript src=http://hq.sinajs.cn/list=sh601006 charset=gb2312></script>
<script type=”text
/javascript>
var elements=hq_str_sh601006.split(
,);
document.write(
current price:+elements[3]);
</script>

这段代码输出大秦铁路(股票代码:601006)的当前股价

current price:14.20

如果你要同时查询多个股票,那么在URL最后加上一个逗号,再加上股票代码就可以了;比如你要一次查询大秦铁路(601006)和大同煤业(601001)的行情,就这样使用URL:

http://hq.sinajs.cn/list=sh601003,sh601001

查询大盘指数,比如查询上证综合指数(000001):

http://hq.sinajs.cn/list=s_sh000001

服务器返回的数据为:

var hq_str_s_sh000001=”上证指数,3094.668,-128.073,-3.97,436653,5458126″;

数据含义分别为:指数名称,当前点数,当前价格,涨跌率,成交量(手),成交额(万元);

查询深圳成指数:

http://hq.sinajs.cn/list=s_sz399001

对于股票的K线图,日线图等的获取可以通过请求http://image.sinajs.cn/…./…/*.gif此URL获取,其中*代表股票代码,详见如下:

查看日K线图:

http://image.sinajs.cn/newchart/daily/n/sh601006.gif

实时股票数据接口大全 sh601006

分时线的查询:

http://image.sinajs.cn/newchart/min/n/sh000001.gif

实时股票数据接口大全 sh000001

日K线查询:

http://image.sinajs.cn/newchart/daily/n/sh000001.gif

实时股票数据接口大全 sh000001

周K线查询:

http://image.sinajs.cn/newchart/weekly/n/sh000001.gif

实时股票数据接口大全 sh000001

月K线查询:

http://image.sinajs.cn/newchart/monthly/n/sh000001.gif

实时股票数据接口大全 sh000001

1.2 Baidu&Google的财经数据
在baidu, google中搜索某只股票代码时,将会在头条显示此股票的相关信息,例如在google搜索601006时,
第一条搜索结果如下图:
通过点击左边的图片我们发现会将此图片链接到sina财经频道上,也就是说google股票数据的获取也是从sina获取。后经抓包分析,发现google也是采用1.1中介绍的接口。

Baidu的股票数据来自baidu的财经频道
http://stock.baidu.com/

[转载]几个数据挖掘相关网站及其评价(2)

mikel阅读(1812)

[转载]几个数据挖掘相关网站及其评价(2) – 左其盛 – 博客园.

一个中文的数据挖掘网络资源的索引:“数据草堂:优秀的数据分析师应该关注哪些网站”(http://blog.sina.com.cn/s/blog_5fc375650102dqri.html)。

一个入门级的网站网站分析在中国(http://www.chinawebanalytics.cn/),这个网站的文章好像基本出自一人之手,其网站地图给出的大纲比较有条理,可以算一个网站分析入门的网站。作者有相关工作经验,写的还不错。

一个中等水平的网站:网站数据分析(http://webdataanalysis.net/)。看了几篇文章,出自同一个作者,感觉算是中文的网络分析中水平还不错的。

一个应该是水平比较高的网站:Occam‘s Razor(http://www.kaushik.net/avinash/)。 作者是数据分析名著《精通Web Analytics 2.0——用户中心科学与在线统计艺术》《精通Web Analytics——来自专家的最佳Web分析策略》两本书的作者,书中介绍说他是Google分析的布道者。看了网站上的一篇讲邮件营销 的:Email Marketing: Campaign Analysis, Metrics, Best Practices(http://www.kaushik.net/avinash/email-marketing-campaign-analysis-metrics-practices/),还是有不少深刻的见解。

一个英文的数据挖掘资源网站:Data Mining and Analytics Resources(http://www.kdnuggets.com/index.html?lg),一位美国的研究数据挖掘的朋友推荐的,在中文的网站上没看到过到这个网站的链接,先记录到这里。

一个流氓网站:互联网分析沙龙(http://www.techxue.com/portal.php)。说它是流氓网站,是因为这个网站中我看过的文章(大概有10来篇)基本都是从别的网站上抄来的,网页上既不注明作者,也不说明出处。

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

mikel阅读(1141)

[转载]Android应用之个人应用软件开发(1)【需求及UI布局】 – zisouTags – 博客园.

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

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

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

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

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

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

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

UI设计:

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

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

当然我们也看到了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

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

在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[i]=(String)actobj[i*2];
}
//BindListView提取数组出来绑定Text内容值
ArrayAdapter adp = new ArrayAdapter(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);
}
});
}
}

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

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

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

[转载]推荐几款.NET下的报表组件(1) - FastReport .NET

mikel阅读(1113)

[转载]推荐几款.NET下的报表组件(1) – FastReport .NET – 趋唯事软件 – 博客园.

FastReport可能对它最熟悉可能还是Delphi程序员了,几乎没有程序员不知 道这款VCL组件的。前几年这个俄罗斯软件公司Fast Reports Inc.公司重写FastReport VCL组件核心代码,同时推出FastReport .NET版,这个.NET当然是完全采用C#代码编写,经过多年的开发,目前版本到了1.7.x了,功能和稳定性都已经相当不错了。

一,推荐理由

  • 紧凑,生成报表速度快: 可以说是目前.NET环境下运行速度最快的一个报表控件
  • 支持的报表样式多:FastReport .Net继承了FastReport VCL没有不能做的报表
  • 报表导出格式齐全:常用的PDF,EXCEL和Docx格式都没有问题,而且所见即所得的导出
  • 成本优势:FastReport .NET每个开发者授权的价格从990元至4990元应该说是不算高,最贵的4990元已经包含了核心源代码。
二,支持的开发环境
FastReport .NET官方显示当前支持WinForm和ASP.NET两种模式,但是好像也有网友在WPF下进行使用,还有SL能不能用目前不能确定。
三,报表设计器
和FastReport VCL一样,.NET版也为开发者提供了一个报表模版设计器,这个设计器既可以在Visual Studio集成环境中打开,也可以独立打包成一个应用程序。当然你想打包成独立的应用程序需要购买专业版以上版本,否则设计模版你只能在Visual Studio进行了。下面我们看一下设计器的截图。

四,丰富的报表元件

FastReport .NET的报表元件很丰富,从最基本的文本元件、图形和直线到图表元件和条形码元件都已经包含。特别,自从微软收购了Dundas Chart,现在最新的Visual Studio 2010中包含了免费的漂亮的Dundas Chart,FastReport把Visual Studio中的图表给整合进来,应该说效果还是非常不错的,这几类图表已经基本上满足我们的需求了。


五,报表类型

FastReport几乎只要能你能想到的报表,基本上都能实现。从简单的List报表,到分组报表、交叉报表和主从报表等,都能直观方便的实现。 另外其内置脚本引擎,你可以报表模版变编写脚本,做出更复杂和个性化的报表。这个我们不多说了,下面看看一个自带的Demo吧。


六,报表导出

常用格式导出没有问题,如PDF,EXCEL,HTML, DOCX等,基本上做到所见即所得的导出效果。


七,总结

FastReport .NET作为一款短小精悍,功能强大的报表控件对.NET开发者来说是一款非常适用的组件,毕竟开发企业信息系统,报表和打印是不能缺少。用一个报表控件 可以很好的解决报表的设计和维护,甚至报表模版交有专人负责,可大大提高工作效率。另外这款产品价格也不贵,比水晶报表便宜好多。

这款报表的官方网站http://www.fast-report.com/en/products/FastReport.Net.html

正版的FastReport .NET国内代理http://www.commuch.com/FastReport_Net-Report.aspx

[转载]百度地图API如何制作“从这里出发”“到这里去”——公交篇

mikel阅读(1093)

[转载]【百度地图API】如何制作“从这里出发”“到这里去”——公交篇 – 酸奶小妹 – 博客园.

摘要:

百度地图首页上的“从这里出发”“到这里去”,一直是开发者们很热衷的一个功能。那么,怎样结合百度的数据库,来制作这个功能呢?让我们一起来学习一下。

——————————————————————————————————————————————-

成品图如下:

———————————————————————————————————————————————

零、基础知识准备

首先,我们来看看公交方案的“从这里去”“到这里来”是怎么制作的。

需要创建一个公交方案,然后使用search功能。

细心的朋友们已经看到了,search接口的start和end参数,其实是可以输入point的。

那么,“从这里出发”到天安门,就应该是search(point,“天安门”)。

从天安门出发“到这里来”,就是search(“天安门”,point)了。

专业地说,这叫做“单边检索”。就是一个参数是string字符串类型,另一个是point经纬度类型。

而这个point,正是检索出来的结果。

————————————————————————————————————————————–

一、如何检索出地图数据

首先,创建一个检索对象。

var local = new BMap.LocalSearch(map,{onSearchComplete: searchComplete});   //构造一个查询

然后使用检索方法,如下:

local.search("希尔顿逸林酒店");

下面,写回调函数。因为AJAX的异步机制,我们需要写回调函数,才能对检索成功后的数据进行操作。

我们写这样一个函数,当检索成功后,返回第一个点,并且利用这个点进行标注的添加。

注意:开发者可以返回多个点,使用循环即可。详见《如何更改百度信息窗口》,里面有返回所有第一页10个结果的代码。

var searchComplete = function (results){
    if (local.getStatus() != BMAP_STATUS_SUCCESS){
        return ;
    }
    var point = results.getPoi(0);
    addMarker(point);
}

标注的添加函数应该包含以下几个要点:

1、marker,就是标注的位置。(用户可自定义marker的图片,更改icon属性即可。见文章《自定义标注和信息窗口》)

2、infowindow,信息窗口信息。可以书写任意的htm内容。我取了百度数据库里的名称、地址、电话和经纬度信息。还放入了“从这里出发”“到这里去”的输入框。

3、添加标注。

4、重新设置中心点和地图级别。

//查询完毕添加自定义标注
function addMarker(point){
var marker = new BMap.Marker(point.point);
var infoWindow = new BMap.InfoWindow("
<div style="line-height: 1.8em; font-size: 12px;"><strong>名称:</strong>"+point.title+"
<strong>地址:</strong>"+point.address+"
<strong>电话:</strong>"+point.phoneNumber+"
<p style="border-top: 1px dashed #44aa99;"></p>
从这里到<input id="point_start" style="border: 1px solid #aaa; background: none;" type="text" value="天安门" /><input onclick="bus_start();" type="button" value="公交" />
从<input id="point_end" style="border: 1px solid #aaa; background: none;" type="text" value="天安门" />到这里<input onclick="bus_end();" type="button" value="公交" />

</div>
");  // 创建信息窗口对象
map.addOverlay(marker);
setTimeout(function(){map.centerAndZoom(point.point,14);marker.openInfoWindow(infoWindow);},500);
}

第一步完成以后,运行你的页面,就是这个样子啦:

————————————————————————————————————————————–

二、公交查询语句“从这里出发”和“到这里来”

首先,创建一个公交导航的对象。

map:map  是说,把公交线路图展现在map地图上。

panel:results  是说,把结果面板,展示在results里面。注意,这里要加上引号。

var transit = new BMap.TransitRoute(map, {renderOptions: {map: map, panel : "results"}});

创建好之后,就开始做公交查询了。

把刚才取到的经纬度,做为起点或者终点,进行公交查询。

function bus_start(){
    transit.search(thisPoint , document.getElementById("point_start").value);
}
function bus_end(){
    transit.search(document.getElementById("point_end").value , thisPoint);
}

公交查询的结果将会显示在results里面。如下图:

————————————————————————————————————————————–

三、全部源代码





公交方案的单边检索
<script src="http://api.map.baidu.com/api?v=1.2" type="text/javascript">
</script>

<input id="myPOI" type="text" value="希尔顿逸林大酒店" /><input onclick="poi_search();" type="button" value="查询地点" />

<script type="text/javascript">// <!&#91;CDATA&#91;
var thisPoint;
//查询完毕添加自定义标注
function addMarker(point){
    var marker = new BMap.Marker(point.point);
    var infoWindow = new BMap.InfoWindow("
<div style='line-height:1.8em;font-size:12px;'><b>名称:</b>"+point.title+"</br><b>地址:</b>"+point.address+"</br><b>电话:</b>"+point.phoneNumber+"

从这里到<input type='text' id='point_start' value='天安门' style='border:1px solid #aaa;background:none;' /><input type='button' onclick='bus_start();' value='公交' /></br>从<input type='text' value='天安门' style='border:1px solid #aaa;background:none;' id='point_end' />到这里<input type='button' onclick='bus_end();' value='公交' /></div>
");  // 创建信息窗口对象
    map.addOverlay(marker);
    setTimeout(function(){map.centerAndZoom(point.point,14);marker.openInfoWindow(infoWindow);},500);
}

//查询完毕的回调函数
var searchComplete = function (results){
    if (local.getStatus() != BMAP_STATUS_SUCCESS){
        return ;
    }
    var point = results.getPoi(0);
    thisPoint = point;
    addMarker(point);
}

var map = new BMap.Map("container");    //创建地图容器
map.centerAndZoom(new BMap.Point(116.404, 39.915), 10); //初始化地图
map.enableScrollWheelZoom();  //启用滚轮缩放
var local = new BMap.LocalSearch(map,{onSearchComplete: searchComplete});   //构造一个查询
var transit = new BMap.TransitRoute(map, {renderOptions: {map: map, panel : "results"}});

//定义三个不同的查询
function poi_search(){
    map.clearOverlays();
    var POI = document.getElementById("myPOI").value;
    local.search(POI);
}
function bus_start(){
    transit.search(thisPoint , document.getElementById("point_start").value);
}
function bus_end(){
    transit.search(document.getElementById("point_end").value , thisPoint);
}
// &#93;&#93;></script>

————————————————————————————————————————————–

四、公交时间与距离

百度地图API的官网上有示例,请点击这里

js大概是这样写的,如下:

 output += plan.getDuration(true) + "\n";             //获取时间
 output += plan.getDistance(true) + "\n";             //获取距离

————————————————————————————————————————————–

五、公交方案

有三种可选,较便捷、可换乘、少步行。请查看示例

类参考如下:

————————————————————————————————————————————–

六、公交线路与公交站信息

查询例如,“104路电车”“975路”等公交车的信息,示例请看这里

————————————————————————————————————————————–

七、不乘地铁的公交方案(新增)

做地铁是不是很贵啊?哈哈,查看示例,返回所有不乘地铁的公交方案。

[转载]helloPe的android项目实战之连连看—实现篇(二)

mikel阅读(1003)

[转载]helloPe的android项目实战之连连看—实现篇(二) – HelloPe – 博客园.

文接上回,之前介绍了项目的架构,进行了功能的分析,同时进行了BoardView类及时间控制类的开发及几个几口的介绍。这次我们将完整的实现游戏棋盘的绘制与touch事件的处理,以及游戏核心算法中连接算法、hint自动帮助算法与判断是否无解算法的实现。这些代码的处理都在继承自BoardView类的GameView类中。

首先在GameView类中添加实现本游戏主要算法的代码,即连接算法的代码(用于判断给定的两个位置的图标能够相连通):

/**
* 本游戏的核心算法,判断两个连接点是否能够连接,这里传进来的就是我们点击的两个点转化成index的值
* @param p1
* @param p2
*/
List
p1Expand = new ArrayList
();
List
p2Expand = new ArrayList
();

public boolean link(Point p1,Point p2){
if(p1.equals(p2)){
return false;
}
path.clear();
if(map[p1.x][p1.y] == map[p2.x][p2.y]){
if(linkDirect(p1,p2)){
path.add(p1);
path.add(p2);
return true;
}
/**
* 一个拐点的判断
*/
Point px = new Point(p1.x,p2.y);         //假设第一种可能点
if(map[p1.x][p2.y] == 0 &amp;&amp; linkDirect(p1,px) &amp;&amp; linkDirect(px,p2)){
path.add(p1);
path.add(px);
path.add(p2);
return true;
}
Point py = new Point(p2.x,p1.y);        //假设第二种可能点
if(map[p2.x][p1.y] == 0 &amp;&amp; linkDirect(p1,py) &amp;&amp; linkDirect(py,p2)){//首先判断map[p2.x][p1.y]中介点是否有图标
path.add(p1);
path.add(py);
path.add(p2);
return true;
}

/**
* 两个折点(corner)
*/
expandX(p1,p1Expand);
expandX(p2,p2Expand);
for(int i = 0; i &lt; p1Expand.size(); i++)
for(int j = 0; j &lt; p2Expand.size(); j++){
if(p1Expand.get(i).x == p2Expand.get(j).x){
if(linkDirect(p1Expand.get(i),p2Expand.get(j))){
path.add(p1);
path.add(p1Expand.get(i));
path.add(p2Expand.get(j));
path.add(p2);
return true;
}
}
}

expandY(p1,p1Expand);
expandY(p2,p2Expand);
for(Point exp1:p1Expand)
for(Point exp2:p2Expand){
if(exp1.y == exp2.y){
if(linkDirect(exp1,exp2)){
path.add(p1);
path.add(exp1);
path.add(exp2);
path.add(p2);
return true;
}
}
}
return false;  //最后三种方式都不能连通,还是要return false ,不然在两个同样的图标下却没有返回值!
}
return false;
}

/**
* 判断直线链接,无拐角,传进来的点值是ScreenToIndex过的了,不过这里传进来的不一定就是我们点击的点,也可能是我们的拐角点(辅助点)
* @param p1
* @param p2
*/
public boolean linkDirect(Point p1,Point p2){

//if(map[p1.x][p1.y] == map[p2.x][p2.y]){
//纵向直线
if(p1.x == p2.x){
int y1 = Math.min(p1.y, p2.y);
int y2 = Math.max(p1.y, p2.y);
boolean flag = true;
for(int y = y1 + 1; y &lt; y2; y++){//这个循环里容易漏掉两个相邻的情况,所以才加上上面的flag样式
if(map[p1.x][y] != 0){
flag = false;
break;
}
}
if(flag){
return true;
}
}
//横直线判断
if(p1.y == p2.y){
int x1 = Math.min(p1.x, p2.x);
int x2 = Math.max(p1.x, p2.x);
boolean flag = true;
for(int x = x1 + 1; x &lt; x2; x++){
if(map[x][p1.y] != 0){
flag = false;
break;
}
}
if(flag){
return true;
}
}
//}
return false;
}
/**
* 向x方向扩展,传进来的点是index过的
* @param p
* @param list
*/
public void expandX(Point p,List
list){
list.clear();
for(int x = p.x + 1; x &lt; xCount; x++){//注意此时可以等于xCount -1了 			if(map[x][p.y] != 0) 				break; 			list.add(new Point(x,p.y)); 		} 		for(int x = p.x -1; x &gt;= 0; x--){
if(map[x][p.y] != 0)
break;
list.add(new Point(x,p.y));
}
}
/**
* 向Y方向扩展,传进来的点是index过的,而list是作为“返回值”需要保存的值
* @param p
* @param list
*/
public void expandY(Point p,List
list){
list.clear();
for(int y = p.y + 1; y &lt; yCount; y ++){ 			if(map[p.x][y] != 0) 				break; 			list.add(new Point(p.x,y)); 		} 		for(int y = p.y -1 ; y &gt;= 0; y--){
if(map[p.x][y] != 0)
break;
list.add(new Point(p.x,y));
}
}

代码中尽量添加注释,此段代码中实现了第一篇文章中进行的算法分析,其中link(Point p1,Point p2)函数作为算法真正的完整实现者,算法的主逻辑有它实现

linkDirect(Point p1,Point p2)函数作为一个工具函数,用于判断给定的两个位置(注意不是两个图标,因为给定的位置不一定含有图标,当我们在判断

”一折型“和“二折型”的情况的时候即使如此)。而expandX(Point p,List<Point> list)与 expandY(Point p,List<Point> list)两个方法的同样作为工具函数,

在判断“二折型”情况时候将会使用,也就是前面所说的“横向扫描”与“纵横扫描”。而对于link(Point p1,Point p2)函数中,我们的逻辑还是将大问题化为小问题处理

最终还是分解到调用linkDirect(Point p1,Point p2)函数来进行“直线型”的处理。

以上即是程序的连接算法的实现,除了程序算法逻辑的理解之外,还需注意在判断的时候,若能够连通,我们已经将

private List<Point> path = new ArrayList<Point>();保存连通路径的path附上值,记得当link函数返回true时,path中即保存了一条相通的路径!完成了

连接算法,下一步我们将依赖于连接算法的实现,完成扫描是否当前地图已经出现无解的情况,因为程序的地图是随机生成的,难免有时候会出现无解的情况;

下面我们将实现判断是否处于无解状态,实现函数:

/**
*用于判断是否当前已经无解
*/
public boolean die(){
for(int y= 1; y &lt; yCount; y++)              //表示从此行中的一个元素开始扫描(起点)
for(int x = 1; x &lt; xCount; x++){        //表示此行中指定列,组成扫描起点
if(map[x][y] != 0){
for(int j = y; j &lt; yCount; j++){//表示正在被扫描的行
if(j == y){//循环中的第一次扫描,为什么特殊?因为此时不一定从一行中的第一个元素开始扫描
for(int i = x + 1; i &lt; xCount - 1; i++){
if(map[x][y] == map[i][j] &amp;&amp; link(new Point(x,y),new Point(i,j))){
return false;
}
}
}else{
for(int i = 1; i &lt; xCount -1; i++){
if(map[x][y] == map[i][j] &amp;&amp; link(new Point(x,y),new Point(i,j)))
return false;
}
}
}
}
}
return true;
}

代码中也有相应注释,每一次判断相当于一次遍历棋盘,同时注意,如果die()函数返回为false,这则证明link()函数返回了true!前面已经 提醒过:当link返回true时,我们用于保存连通路径的path对象中已经保存了一条连通路径的点的集合,只不过在die()函数中运行得到的是按遍 历顺序而来的,并不是我们所指定的两个始点与终点两个图标;所以在这儿,可以借die()的判断,完成我们算法实现的第三个功能,即hint的自动帮助!

/**
* 当点击help按钮时候调用,会帮助玩家消除一对图标
*/
public void autoHelp(){
if(help == 0){
//soundPlay.play(ID_SOUND_ERROR, 0);
return ;
}else{
//soundPlay.play(ID_SOUND_TIP, 0);
help--;
toolsChangedListener.onTipChanged(help);
drawLine(path.toArray(new Point[] {}));
refreshHandler.sendRefresh(500);
}
}

当然此处需要介绍一下最后一行代码的来历:

class RefreshHandler extends Handler{

@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if(msg.what == REFRESH_VIEW){
GameView.this.invalidate();
if(win()){
setMode(WIN);
isStop = true;
isContinue = false;
}else if(die()){    //调用一次die方法!此时如果die返回为false,即还能够连通
change();       //由于die中使用link方法检测,所以此时path中的值又添加了进去,
}                   //这对于我们使用autoHelp方法提供便利!!!
}
}
/**
*
* @param delayTime
*/
public void sendRefresh(int delayTime){
Message msg = new Message();
this.removeMessages(0);
msg.what = REFRESH_VIEW;
this.sendMessageDelayed(msg, delayTime);
}
}

当然对于是否已经为赢了的判断win()函数比较简单,就是扫描棋盘,如果所有位置map值都为了0,即赢了,若不是,还未完成;这里就不贴代码了。

GameView类中还有一个职能就是初始化一张棋盘:

/**
* 初始化地图
*/
public void initMap(){
int x = 1;
int y = 0;
for(int i = 1; i &lt; xCount -1; i++)
for(int j =1; j &lt; yCount -1; j++){
map[i][j] = x;
if(y == 1){
x ++;
y = 0;
if(x == iconCounts){
x = 1;
}
}else{
y = 1;
}
}
change();
GameView.this.invalidate();
}

我们初始化棋盘时,利用前面讲解的初始算法技术,遍历棋盘,先将棋盘填满,但是填满首先还有一个规则就是每一种图标的填入必须同时填入两张,是为每种图标 都为偶数个而设定!介绍一下最后调用的change()函数,也是出自于第一篇的棋盘初始算法,用于随机将棋盘中的图标打乱:

/**
* 随机将现有的布局打乱,重新布局,map中现有图标数量不变,相当于一次refresh
*/
public void change(){
Random random = new Random();
int tmp,xtmp,ytmp;
for(int x = 1;x &lt; xCount -1; x++){
for(int y = 1; y &lt; yCount -1; y++){
xtmp = 1 + random.nextInt(xCount -2);
ytmp = 1 + random.nextInt(yCount - 2);
tmp = map[x][y];
map[x][y] = map[xtmp][ytmp];
map[xtmp][ytmp] = tmp;
}
}
if(die()){              //如出现无解情况,即需要再次随机重新打乱
change();
}
}

GameView类还是一个View,在此类中我们还要重写View的onTouchEvent方法:

/**
	 * 对于选择的处理,如果是第一次按下,则将其加入到selected当中,
	 * 若是第二次(selected.size()==1),则先判断能不能连通
	 */
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		int sx = (int)event.getX();
		int sy = (int)event.getY();
		Point p = screenToIndex(sx, sy);
		if(map[p.x][p.y] != 0){
			if(selected.size() == 1){
				if(link(selected.get(0),p)){   //能够连通,path中的数据是在link判断时如果返回真,方法内部就已经将数据添加进去
					selected.add(p);
					drawLine(path.toArray(new Point[]{}));
					refreshHandler.sendRefresh(500);
				}else{         //不能够连通
					selected.clear();
					selected.add(p);
					GameView.this.invalidate();   //在这儿说一下refreshHanler.sendRefresh(int) 跟单纯调用GameView.this.invalidate()区别
					                              //前者除了后者只拥有的刷新显示之外,还加了是否已经无解跟是否已经完成任务的判断的操作。
				}
			}else{//此时的selected中的size只能等于0
				selected.add(p);
				GameView.this.invalidate();
			}
		}
		return super.onTouchEvent(event);
	}

方法中用到的selected是BoardView中的protected List selected = new ArrayList();代码中对于功能及实现有相应的注释。

到此我们可以提供接口startGame以供在程序的activity中调用:

public void startPlay(){
		help = 3;
		refresh = 3;
		isContinue = true;
		isStop = false;
		toolsChangedListener.onRefreshChanged(refresh);
		toolsChangedListener.onTipChanged(help);	
		leftTime = totalTime;
		initMap();
		refreshTime = new RefreshTime();
		Thread t = new Thread(refreshTime);    //注意正确启动一个实现Runnable接口的线程类
		t.start();
		GameView.this.invalidate();
	}

注意GameView中并没有实现相关的自定义的接口,而是我们将会在程序的activity中实现项目中涉及的三个接口,但是,我们可以在GameView中进行注册:

public void setOnTimerListener(OnTimerListener onTimerListener){
		this.timerListener = onTimerListener;
	}
	public void setOnToolsChangedListener(OnToolsChangeListener toolsChangeListener){
		this.toolsChangedListener = toolsChangeListener;
	}
	public void setOnStateChangeListener(OnStateListener stateListener){
		this.stateListener = stateListener;
	}

然后在程序的activity中调用GameView的相关函数进行初始化注册。这样,根据多态性的原理,在GameView当中调用的相关接口中的函数,也就是activity中实现的接口中的函数。这也是Android程序中interface实现与注册的一种方式。

以上已经基本描述了GameView的功能与最主要的实现。总结一下,实现了map的初始化,重写了touch时间的处理函数,完成了程序的连接算法,hint自动帮助算法,die的无解判断算法,还有用于更新显示的继承自Handler的内部类的实现。整个项目也已经基本成型了。

重申一下:之所以写本系列的文章,为了记录Android小项目的经历,增加实战的能力,做个总结。并不是为了做出多么新颖的项目,当然也是向不少的网友学习了的!

[转载]helloPe的android项目实战之连连看—实现篇(一)

mikel阅读(1271)

[转载]helloPe的android项目实战之连连看—实现篇(一) – HelloPe – 博客园.

在上一篇文章helloPe的android项目实战之连连看—设计篇中,我们进行了对Android中连连看的项目的设计,包括功能模块的划分以及核心算法的设计。此文章接上文对Android平台连连看程序进入实现阶段。在此项目中,根据上文中对于功能的分析,我们将实现以下类(下面即是工程的文件目录):

在开发中,我们遵循由下向上的方式,也就是说,我们首先开发位于最底层的类,这种类并不依赖于其他的我们需要实现的类。根据上文的分析,首先我们开 发在表示层模块中的界面显示类,首先是BoardView类,在Android平台下,采用继承自View类的方式,看此类的代码,代码中尽量添加了详细 的注释:

package nate.llk.view;
/**
* **********************************************
* @author HelloPe
************************************************
*/
public class BoardView extends View {
/**
* xCount x轴方向的图标数+2
*/
protected static final int xCount = 10;
/**
* yCount y轴方向的图表数+2
*/
protected static final int yCount = 12;
/**
* map 连连看游戏棋盘,map中添加的int型在程序中的意思是index,而不是屏幕坐标!
*/
protected int[][] map = new int[xCount][yCount];
/**
* iconSize 图标大小,图标是正方形,所以一个int变量表示即可
*/
protected int iconSize;
/**
* iconCounts 图标的数目
*/
protected int iconCounts=19;
/**
* icons 所有的图片
*/
protected Bitmap[] icons = new Bitmap[iconCounts];
/**
* path 可以连通点的路径
*/
private Point[] path = null;
/**
* selected 选中的图标
*/
protected List
selected = new ArrayList
();

/**
* 构造函数
* @param context
* @param attrs
*/
public BoardView(Context context, AttributeSet attrs) {
super(context, attrs);
calIconSize();
Resources r = getResources();
//载入连连看中的图标资源
loadBitmaps(1, r.getDrawable(R.drawable.fruit_01));
loadBitmaps(2, r.getDrawable(R.drawable.fruit_02));
loadBitmaps(3, r.getDrawable(R.drawable.fruit_03));
loadBitmaps(4, r.getDrawable(R.drawable.fruit_04));
loadBitmaps(5, r.getDrawable(R.drawable.fruit_05));
loadBitmaps(6, r.getDrawable(R.drawable.fruit_06));
loadBitmaps(7, r.getDrawable(R.drawable.fruit_07));
loadBitmaps(8, r.getDrawable(R.drawable.fruit_08));
loadBitmaps(9, r.getDrawable(R.drawable.fruit_09));
loadBitmaps(10, r.getDrawable(R.drawable.fruit_10));
loadBitmaps(11, r.getDrawable(R.drawable.fruit_11));
loadBitmaps(12, r.getDrawable(R.drawable.fruit_12));
loadBitmaps(13, r.getDrawable(R.drawable.fruit_13));
loadBitmaps(14, r.getDrawable(R.drawable.fruit_14));
loadBitmaps(15, r.getDrawable(R.drawable.fruit_15));
loadBitmaps(16, r.getDrawable(R.drawable.fruit_17));
loadBitmaps(17, r.getDrawable(R.drawable.fruit_18));
loadBitmaps(18, r.getDrawable(R.drawable.fruit_19));
}
/**
* 计算图标的大小
*/
private void calIconSize(){
//取得屏幕的大小
DisplayMetrics dm = new DisplayMetrics();
((Activity) this.getContext()).getWindowManager()
.getDefaultDisplay().getMetrics(dm);
iconSize = dm.widthPixels/( xCount );
}
/**
* 函数目的在于载入图标资源,同时将一个key(特定的整数标识)与一个图标进行绑定
* @param key 特定图标的标识
* @param d drawable下的资源
*/
public void loadBitmaps(int key,Drawable d){
Bitmap bitmap = Bitmap.createBitmap(iconSize,iconSize,Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
d.setBounds(0, 0, iconSize, iconSize);
d.draw(canvas);
icons[key]=bitmap;  //未用0 号index
}
/**
* View自带的,但是在此方法中,有画路径(删除联通的两个图标),
* 绘制棋盘的所有图标(也可理解为刷新,只要此map位置值&gt;0)
* 放大第一个选中的图标(selected.size() == 1)
*/
@Override
protected void onDraw(Canvas canvas) {
/**
* 绘制连通路径,然后将路径以及两个图标清除
*/
if(path != null &amp;&amp; path.length &gt;= 2){
for(int i = 0; i &lt; path.length - 1;++i){
Paint paint = new Paint();
paint.setColor(Color.BLUE);
paint.setStrokeWidth(3);
paint.setStyle(Paint.Style.STROKE);
Point p1 = indexToScreen(path[i].x,path[i].y);
Point p2 = indexToScreen(path[i + 1].x,path[i + 1].y);
canvas.drawLine(p1.x + iconSize/2, p1.y + iconSize/2,
p2.x + iconSize/2, p2.y + iconSize/2, paint);
}
map[path[0].x][path[0].y] = 0;
map[path[path.length - 1].x][path[path.length -1].y] = 0;
selected.clear();
path = null;
}
/**
* 绘制棋盘的所有图标 当这个坐标内的值大于0时绘制
*/
for(int x = 1;x &lt; xCount - 1; ++x){
for(int y = 1; y &lt; yCount -1; ++y){ 				if(map[x][y]&gt;0){
Point p = indexToScreen(x, y);
canvas.drawBitmap(icons[map[x][y]], p.x,p.y,null);
}
}
}
/**
* 绘制选中图标,当选中时图标放大显示
*/
//for(Point position:selected){
if(selected.size() &gt; 0){
Point position = selected.get(0);
Point p = indexToScreen(position.x, position.y);
if(map[position.x][position.y] &gt;= 1){
canvas.drawBitmap(icons[map[position.x][position.y]],
null,
new Rect(p.x-5, p.y-5, p.x + iconSize + 5, p.y + iconSize + 5), null);
}
}
super.onDraw(canvas);
}

/**
* 工具方法
* @param x 数组中的横坐标
* @param y 数组中的纵坐标
* @return 将图标在数组中的坐标转成在屏幕上的真实坐标
*/
public Point indexToScreen(int x,int y){
return new Point(x * iconSize,y * iconSize);
}
/**
* 工具方法
* @param x 屏幕中的横坐标
* @param y 屏幕中的纵坐标
* @return 将图标在屏幕中的坐标转成在数组上的虚拟坐标
*/
public Point screenToIndex(int x,int y){
int xindex = x / iconSize;
int yindex = y / iconSize;
if(xindex &lt; xCount &amp;&amp; yindex &lt; yCount){
return new Point(xindex,yindex);
}else{
return new Point(0,0);
}
}
/**
* 传进来path数据更新显示,也就是将能够连接的图标消除
* @param path
*/
public void drawLine(Point[] path) {
this.path = path;
this.invalidate();
}

}

此类当中,主要是实现了将连连看图标资源的载入并且使之与一个特定的int型key相绑定,所以在后面的对于图标的贴图,我们能够更加方便的操作。当然

此类中还需要存在一些必要的工具函数,比如说screenToIndex方法等,因为我们是自定义View在屏幕上绘图,需要用到屏幕坐标,但是同时,连连看游戏

中,我们还需要知道图标的索引(由于图标都是等长等宽,容易实现屏幕坐标与index索引之间的转换),以使方便操作。当然,此类中最重要的还是重写

的onDraw函数;此函数中首先判断path是否为null并且是否两个及以上的元素,我们之前定义path变量时,是将其作为保存连通路径的工具。(path中

的值也就是连通路径我们将在连接算法实现时中加入)这里我们首先在onDraw函数中绘制出线条(如果连通),随后将路径的首尾中的map值设为0,程

序中,第0行与最后一行map值始终为0,第0列与最后一列map值始终为0,map中的值0为0代表此处已经没有了图标,根据前面与图标资源的绑定值与

map中的值对应,map中的值为几则在相应的index上贴上相应的图标。在onDraw函数中,还有一个功能就是将选择的第一个图标放大,以提醒玩家

最后绘制(贴图),如前面所说,map值为多少就在对应位置贴上相应的图标资源,有前面载入资源时可知并没有对应于0的图标资源,为0时即不贴图。

为了防止代码混乱,上面的BoardView 类并没有实现全部的功能,如touch事件的监听,连接算法的实现,判断是否无解等等。所以我们将BoardView

类进行扩展,继承BoardView的GameView(这样做也使代码不至于太混乱)。限于篇幅,我们可以先将GameView中用于监听剩余时间的内部类实现

(该类实现了Runnable接口):

/**
* 用于更新剩余时间的线程
* @author helloPe
*
*/
class RefreshTime implements Runnable{

@Override
public void run() {
if(isContinue){
while(leftTime &gt; 0 &amp;&amp; !isStop){
timerListener.onTimer(leftTime);
leftTime --;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
if(isStop &amp;&amp; leftTime &gt; 0){
if(win())
;//setMode(WIN);
else
setMode(PAUSE);
}
//setMode(LOSE);
else if(leftTime == 0){
setMode(LOSE);
}
}
}
/**
* 停止显示的时间
*/
public void stopTimer(){
isStop = true;
isContinue = false;
}
/**
* 设置继续
*/
public void setContinue(){
isContinue = true;
isStop = false;
refreshTime = new RefreshTime();
Thread t = new Thread(refreshTime);    //注意正确启动一个实现Runnable接口的线程
t.start();
}

上面已经提过,此线程用于控制游戏的时间。

在此,再介绍自定义的几个接口,

public interface OnStateListener{
public void OnStateChanged(int StateMode);
}

只含有一个方法,主要对于游戏状态的变换的监听,比如pause,stop等等。

public interface OnTimerListener{
public void onTimer(int leftTime);
}

用于监听剩余时间,与上面线程不同的是,此方法中利用上面线程的leftTime的结果,主要用于更新游戏中用于提醒玩家的时间进度条。

public interface OnToolsChangeListener{
public void onRefreshChanged(int count);
public void onTipChanged(int count);
}

tool即是我们的游戏中提供给玩家的两个工具,一个是refresh一下游戏界面,即将现有的棋盘重新打乱(当然,现有图表数量不变),另一个是之前提过的hint的自动帮助功能,帮助玩家找到一组能够连通的图标。当然,这两种工具都有次数的限制。

BoardView类及时间线程类的开发与介绍到此,后面我们将完整的实现游戏棋盘的绘制与touch事件的处理,以及游戏核心算法中连接算法、hint自动帮助算法与判断是否无解算法的实现。这些代码的处理都在继承自BoardView类的GameView类中。

之所以写本系列的文章,为了记录android小项目的经历,增加实战的能力,做个总结。并不是为了做出多么新颖的项目,当然也是向不少的网友学习了的!

[转载]Android的程序解码与XML文件解码

mikel阅读(1037)

[转载]Android的程序解码与XML文件解码 – 刘凯文 – 博客园.

首先,怀着无比激动的心情写下这篇日志…..

Googles真的很给力….让我有幸看到Android应用程序的内部源码….

下面开始言归正传:

Android的应用程序是由两部分组成的.

1.*.class文件

2.*.xml文件  解码时候需要使用到不同的工具…

下面开始介绍*.class(类文件的解码)

需要用到的工具:

dex2jarJD-GUI

dex2jar下载地址:http://laichao.googlecode.com/files/dex2jar-0.0.7-SNAPSHOT.zip

JD-GUI下载地址:
windows版JD-GUI:
http://laichao.googlecode.com/files/jdgui.zip
Linux版JD-GUI:http://laichao.googlecode.com/files/jd-gui-0.3.2.linux.i686.tar.gz

A:将*.apk文件的后缀修改成*.zip,然后解压,会在文件夹内发现一个叫classes.dex的文件

B:将dex2jar解压后放到C盘根目录,然后将classe.dex放到这个文件夹中来

然后在开始运行中输入CMD,

将路径定位到dex2jar.bat所在的文件夹(dex2jar.bat为dex2jar解压后文件夹内存在的一个*.BAT文件)

然后输入:dex2jar.bat classes.dex

(这里有可能会报错,如果报错好好看一下JAVA的环境变量是什么,配置的对不对)

C:如果一切正常就会解码出来一个*.jar文件

D:用刚才提及到的JD-GUI来解码*.jar文件 (windows环境的直接拖上去可以)

E:很多公司开发出来的源码都是修改了类名,方法名的- -这个比较恶心,也没有什么好办法,只能费点眼神仔细看了….

下面是*.xml文件的解码

需要用到的工具:

apktool1.4.1.tar.bz2

apktool-install-windows-r04-brut1.tar.bz2

这两个工具可以在Google官方提供的URL地址:http://code.google.com/p/android-apktool/

上下载

然后解压,

A:两个压缩包内的所有文件都要放在同一个路径下,本人放的还是C盘根目录

B:将需要解码的*.apk文件放到和步骤A中解压的文件相同的路径下(本人放的依旧是C盘根目录)

C:开始—>运行输入CMD,然后定位到C盘,在命令提示框内输入:apktool d C:\*.apk  C:\***

(*.apk为需要解码的应用程序,***为文件夹名称)

D:解码后就能清晰的看到程序内所有用到的*.XML文件啦…包括布局文件和AndroidManifest.xml文件

^_^

[转载]存储过程异常处理

mikel阅读(824)

[转载]【存储过程】异常处理 – Shoubin – 博客园.

在前一篇博客中,江南听雨 提出存储过程中的异常处理。  借此写一点关于存储过程的东西。

还是以例子为主要内容。有不合适的地方请大家指出。

我使用的是SQLServer2008,所举的例子也是在这个环境下进行了。

1、表结构(Course)

2、存储过程

就以插入数据为例,其他的可以照着写就行了。

编程语言都有异常的捕获与处理, 在 SQLServer2008 中也是这样子的。

对会出现异常的语句加上 begin try……end try ,然后进行异常捕捉:begin catch……end catch即可。

相关的 错误代码详解 很容易就能找到。

代码如下:

 1 Create proc sp_Insert_Course
 2     @No char(10),
 3     @Name varchar(20),
 4     @Comment varchar(50),
 5     @rtn int output
 6 as
 7     begin try
 8         insert into Course values(@No,@Name,@Comment)
 9         set @rtn=1
10     end try
11     begin catch
12         set @rtn=@@ERROR
13         
14         --辅助信息
15         --select ERROR_LINE() as Line,
16         --    ERROR_MESSAGE() as message1,
17         --    ERROR_NUMBER() as number,
18         --    ERROR_PROCEDURE() as proc1,
19         --    ERROR_SEVERITY() as severity,
20         --    ERROR_STATE() as state1
21     end catch

3、存储过程执行

相关代码如下:

1 declare
2     @rtn int
3 exec sp_Insert_Course '114','语文','',@rtn output
4 print @rtn

执行结果:

如果程序有异常,把异常代码返回,然后再进行相关的处理即可。

SQL Server中的异常处理和别的数据库(如Oracle)的有点差异,但是基本思想差不多,都是在最后捕获异常。

希望能够对大家有所帮助。