当前位置:  编程技术>移动开发
本页文章导读:
    ▪画图技能        画图技巧 本文来自http://blog.csdn.net/hellogv/ ,引用必须注明出处!        常用控件说了不少,现在说说手机开发中也常用到的画图。要掌握Android的画图,首先就要了解一下,基本用到.........
    ▪ 2D手机游戏的及时阴影效果        2D手机游戏的即时阴影效果         转载要注明作者、出处哟。        前段时间在做可以兼容J2ME和Android的ARPG引擎,获得一些心得。2D手机游戏似乎画面上没什么突破,几乎都是靠美.........
    ▪ ActivityGroup兑现Tab分页标签       ActivityGroup实现Tab分页标签 很多客户端软件和浏览器软件都喜欢用Tab分页标签来管理内容,除了可以用TabHost控件,还可以用ImageButton + ActivityGroup实现Tab分页标签。使用ImageButton + ActivityGroup.........

[1]画图技能
    来源: 互联网  发布时间: 2014-02-18
画图技巧
本文来自http://blog.csdn.net/hellogv/ ,引用必须注明出处!

        常用控件说了不少,现在说说手机开发中也常用到的画图。要掌握Android的画图,首先就要了解一下,基本用到的图形接口:

1.Bitmap,可以来自资源/文件,也可以在程序中创建,实际上的功能相当于图片的存储空间;

2.Canvas,紧密与Bitmap联系,把Bitmap比喻内容的话,那么Canvas就是提供了众多方法操作Bitamp的平台;

3.Paint,与Canvas紧密联系,是"画板"上的笔刷工具,也用于设置View控件上的样式;

4.Drawable,如果说前三者是看不见地在内存中画图,那么Drawable就是把前三者绘图结果表现出来的接口。Drawable多个子类,例如:位图(BitmapDrawable)、图形(ShapeDrawable)、图层(LayerDrawable)等。



本文主要讲解如何在ImageView画图,以及如何直接在Button(继承View的控件)上面绘制自定义图像。


直接把资源图片画出来


在ImageView上画图以及绘字


直接在控件背景上画图

main.xml的源码:
<?xml version="1.0" encoding="utf-8"?>  
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:orientation="vertical"  
    android:layout_width="fill_parent"  
    android:layout_height="fill_parent"  
    >  
<Button android:id="@+id/Button01" android:layout_width="fill_parent" android:layout_height="44px" android:text="显示资源图片"></Button>  
<Button android:id="@+id/Button02" android:layout_width="fill_parent" android:layout_height="44px" android:text="显示并绘画资源图片"></Button>  
<Button android:id="@+id/Button03" android:layout_height="44px" android:layout_width="fill_parent" android:text="在控件上绘图"></Button>  
<ImageView android:id="@+id/ImageView01" android:layout_width="wrap_content" android:layout_height="wrap_content"></ImageView>  
  
</LinearLayout>  


程序的源码:
package com.testDraw;  
  
import android.app.Activity;  
import android.content.res.Resources;  
import android.graphics.Bitmap;  
import android.graphics.Bitmap.Config;  
import android.graphics.BitmapFactory;  
import android.graphics.Canvas;  
import android.graphics.Color;  
import android.graphics.Paint;  
import android.graphics.Typeface;  
import android.graphics.drawable.BitmapDrawable;  
import android.graphics.drawable.Drawable;  
import android.os.Bundle;  
import android.view.View;  
import android.widget.Button;  
import android.widget.ImageView;  
  
public class testDraw extends Activity {  
      
    ImageView iv;  
    Button btn1,btn2,btn3,btn4;  
    Resources r;  
    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.main);  
        iv=(ImageView)this.findViewById(R.id.ImageView01);  
        btn1=(Button)this.findViewById(R.id.Button01);  
        btn2=(Button)this.findViewById(R.id.Button02);  
        btn3=(Button)this.findViewById(R.id.Button03);  
  
        btn1.setOnClickListener(new ClickEvent());  
        btn2.setOnClickListener(new ClickEvent());  
        btn3.setOnClickListener(new ClickEvent());  
          
        r = this.getResources();  
  
    
    }  
    class ClickEvent implements View.OnClickListener {  
  
        public void onClick(View v) {  
            if(v==btn1)//显示资源图片  
            {//功能等效  
                //iv.setBackgroundResource(R.drawable.icon);//打开资源图片  
                Bitmap bmp=BitmapFactory.decodeResource(r, R.drawable.icon);//打开资源图片  
                iv.setImageBitmap(bmp);  
            }  
            else if(v==btn2)//显示并绘画资源图片  
            {  
                Bitmap bmp=BitmapFactory.decodeResource(r, R.drawable.icon);//只读,不能直接在bmp上画  
                Bitmap newb = Bitmap.createBitmap( 300, 300, Config.ARGB_8888 );  
                  
                Canvas canvasTemp = new Canvas( newb );  
                canvasTemp.drawColor(Color.TRANSPARENT);  
                  
                Paint p = new Paint();  
                String familyName ="宋体";  
                Typeface font = Typeface.create(familyName,Typeface.BOLD);  
                p.setColor(Color.RED);  
                p.setTypeface(font);  
                p.setTextSize(22);  
                canvasTemp.drawText("写字。。。",50,50,p);  
                canvasTemp.drawBitmap(bmp, 50, 50, p);//画图  
                iv.setImageBitmap(newb);  
            }  
            else if(v==btn3)//直接在Button上绘图  
            {  
                Bitmap newb = Bitmap.createBitmap( btn3.getWidth(), btn3.getHeight(), Config.ARGB_8888 );  
                Canvas canvasTemp = new Canvas( newb );  
                canvasTemp.drawColor(Color.WHITE);  
                Paint p = new Paint();  
                String familyName = "宋体";  
                Typeface font = Typeface.create(familyName, Typeface.BOLD);  
                p.setColor(Color.RED);  
                p.setTypeface(font);  
                p.setTextSize(20);  
                canvasTemp.drawText("写字。。。", 30, 30, p);  
                Drawable drawable = new BitmapDrawable(newb);  
                btn3.setBackgroundDrawable(drawable);  
            }  
        }  
          
    }  
  
}  
1 楼 a105865708 2011-03-17  
Bitmap bmp=BitmapFactory.decodeResource(r, R.drawable.icon);//只读,不能直接在bmp上画     



decodeResource()获得的bitmap真的是只读的吗?

但是我发现我:
 Bitmap b = BitmapFactory.decodeResource(getResources(), R.drawable.aa);
 Log.v("1", b.isMutable()+"");


结果:
03-17 10:50:13.245: VERBOSE/1(671): true  是可变的。

真的很不解 

可以加QQ请教下吗?

QQ:105865708

    
[2] 2D手机游戏的及时阴影效果
    来源: 互联网  发布时间: 2014-02-18
2D手机游戏的即时阴影效果

        转载要注明作者、出处哟。

        前段时间在做可以兼容J2ME和Android的ARPG引擎,获得一些心得。2D手机游戏似乎画面上没什么突破,几乎都是靠美工把地图画得华丽一些,然后加一些云朵、光晕的贴图,再弄点下雨、下雪啥的,已经见怪不怪了。看了一些前几年的PC游戏,同样是2D,像暗黑就有模拟的光照效果,场景有明暗之分,人物也阴影效果。目前手机游戏有点类似当年的形态,当然即时是现在的手机也无法与当年的PC性能抗衡。要在2D手机游戏上实现这些效果肯定要降低效果的质量。

 

      先来说阴影,原理其实很简单,比如要给一个人物精灵绘制阴影:

      1)将精灵原图按比例拉伸、旋转

      2)转换成带alpha效果的黑色图片

      3)绘制到人物脚下

 

      OK!既然这么简单,立马实现到现有的游戏中去看看效果!

      结果,效果是出来了,速度却慢得惊人,由于是即时绘制,在我的N85上帧速只有5~8左右,这还只是一个人物精灵的绘制,如果给每个NPC都加上阴影……嗯,你懂的。

 

      好吧,这可是即时运算,我们得找找影响CPU发挥的瓶颈在哪:

       1)图像的拉伸、旋转网上有很多算法,什么插值法、扫描法……前辈们总结了很多,这可是在虚拟机上跑,过高的时间复杂度,甚至涉及浮点运算肯定会让速度大打折扣。

       2)还有,获取原图的RGB信息,经过一系列的翻转、拉伸,然后新建个动态图像,把RPG值转成黑色填进去,再调整alpha值,再贴到指定位置……这么折腾N85居然能做到5帧,太给力了!

 

       了解了瓶颈所在,下面停止扯淡,介绍一下我的优化方法:

       跳过拉伸、旋转操作,每帧都做这么大开销的操作就是手机电池也不会答应。我们可以直接扫描图像的RGB信息,扫描到非透明的RGB值时计算出对应点的位置(计算这里涉及三角函数,为了提升性能以及兼容MIDP1.0,建议用查表法)。跳过新建图像以及alpha调整的操作,我们可以预先建立好一个半透明的黑色影子图片来贴图。

 

       coding...经过一系列的折腾,效果出来了:

 

        感觉还不错吧?场景中有4棵树绘制了阴影,N85实机帧数是20上下。(这是WTK2.5的模拟器截图,由于还开启了引擎的模拟明暗效果,所以帧数下降到了12。)

 

        等等,N85在主流J2ME手机里算不错的,一个影子效果就让PFS降到了20,那以后加上模拟水波、模拟光照、模拟天气等等效果,不是得卡死?嗯……让我来进一步优化,不过这次可就要稍微降低一些影子的质量了:

        逐个像素扫描图片,运算量也是相当惊人的,80x32的一棵小树就要判断2560次!我们可以间隔着扫描,比如扫描某行RGB信息时,扫描1个像素然后跳过下面4个像素再扫描下一个,这样影子效果可能有一些偏差,但是大致轮廓还是很清晰的。(如果扫描的像素非透明就用准备好的半透明影子图片绘制一个1x4的影子,跳过接下来4个像素继续扫描,继续绘制……)来看效果:

跳过2个像素

 

跳过4个像素

       

        FPS提升了5倍!好吧,你应该有所启发,横向、纵向扫描越过几个像素完全由你控制,我们可以理解为扫描精度。来更进一步优化,即便是跳着扫描,仍然需要判断很多次,而我们只是要获得精灵的大致轮廓,画出阴影而已。我们完全可以从图片的两边扫描不透明点的起始位置,然后计算不透明区域的长度,根据这个长度直接贴图!

        好吧,光放几张鸟图,不贴代码是不厚道的,下面是影子绘制部分的核心代码(写的比较烂,望海涵):

    /** 利用透明图片绘制向下的影子
     * @param g Graphics  画布对象
     * @param img Image  要绘制阴影的原图
     * @param px int  绘制x位置
     * @param py int  绘制y位置
     * @param height int  影子高度(<=原图像素高度)
     * @param scanSkip int  扫描跳过的像素个数(1最高精度,建议用2)
     * @param cot256 int  影子角度的cot值(这里是查表法得来的256倍)
     */
    public static void drawTransShadowDown(Graphics g, Image img, int px,
	    int py, int height, int scanSkip, int cot256) {

	int w = img.getWidth();
	int h = img.getHeight();
	int pels[] = new int[w];
	int ofx = 0;
	int scanH = 256 * h / height;

	int startX = 0;
	int endX = 0;
	int rowIn = 0;
	int scanIn = (h - 1) * 256;
	g.setColor(0x000000);

	while (scanIn >= 0) {
	    //跳过扫描?
	    if (rowIn % scanSkip == 0) {
		img.getRGB(pels, 0, w, 0, scanIn >> 8, w, 1);
		//扫描起始位置
		for (int j = 0; j < w; j++) {
		    if ((pels[j] >> 24) == -1) {
			startX = j;
			break;
		    }
		}
		//扫描结束位置
		for (int j = w - 1; j >= 0; j--) {
		    if ((pels[j] >> 24) == -1) {
			endX = j;
			break;
		    }
		}
		//这个方法是我自己里面封装的,类似DrawRegion,transImg是一张半透明黑色图片
		BaseCanvas.drawImage(g, transImg, 0, 0, endX - startX + 1,
			scanSkip, 0, px + (ofx >> 8) + startX, py + rowIn, 20);
	    }
	    ofx += cot256;
	    rowIn++;
	    scanIn -= scanH;
	}
    }

 

      查表法求三角函数:

    //sin(0°) to sin(90°)    all *256
    public final static int SIN_TABLE[] = {
        0, 4, 8, 13, 17, 22, 26, 31, 35, 39,
        44, 48, 53, 57, 61, 65, 70, 74, 78, 83,
        87, 91, 95, 99, 103, 107, 111, 115, 119, 123,
        127, 131, 135, 138, 142, 146, 149, 153, 156, 160,
        163, 167, 170, 173, 177, 180, 183, 186, 189, 192,
        195, 198, 200, 203, 206, 208, 211, 213, 216, 218,
        220, 223, 225, 227, 229, 231, 232, 234, 236, 238,
        239, 241, 242, 243, 245, 246, 247, 248, 249, 250,
        251, 251, 252, 253, 253, 254, 254, 254, 254, 254,
        255
    };


    /** 查表法求SIN值
     *
     * @param angle int 0到360度
     * @return int  返回SIN值的256倍
     */
    public static int sin256(int angle) {
        angle %= 360; // 360 degrees
        if (angle <= 90) { // 0..90 degrees
            return SIN_TABLE[angle];
        }
        else if (angle <= 180) { // 90..180 degrees
            return SIN_TABLE[180 - angle];
        }
        else if (angle <= 270) { // 180..270 degrees
            return -SIN_TABLE[angle - 180];
        }
        else { // 270..360 degrees
            return -SIN_TABLE[360 - angle];
        }
    }

    public static int cos256(int angle) {
        return sin256(angle + 90); // i.e. add 90 degrees
    }

    public static int cot256(int angle){
        return cos256(angle)*256/Math.sin256(angle);
    }

    public static int tan256(int angle){
        return sin256(angle)*256/Math.cos256(angle);
    }

 

      最后,有一个问题值得注意,细心观察自然界的影子,其实并不是直接旋转一下原图的效果,而是根据光源的位置投影而来的。网上有些那原图直接翻转的方法其实是错的,本文的方法也不太正确,但至少在2D游戏里看上去像那么回事,哈哈,看图为证~ 

 

 

 

      刚开始在这写点东西,技术不足还请多多指教。我对J2ME、Android游戏开发很感兴趣,望有朋友能一起交流QQ:350751373。


    
[3] ActivityGroup兑现Tab分页标签
    来源: 互联网  发布时间: 2014-02-18
ActivityGroup实现Tab分页标签
很多客户端软件和浏览器软件都喜欢用Tab分页标签来管理内容,除了可以用TabHost控件,还可以用ImageButton + ActivityGroup实现Tab分页标签。使用ImageButton + ActivityGroup实现Tab分页标签,主要是把一个Sub Activity(子Activity)的Window作为View添加到ActivityGroup所指定的容器中,本文使用LinearLayout作为容器装载Sub Activity。

接下来贴出本例运行的效果图:



以下是切换时Sub Activity的生存周期的状态变化:



从subActivity1切换到subActivity2的时候,会彻底释放subActivity1的资源。

主Activity的main.xml的源码如下:
<?xml version="1.0" encoding="utf-8"?>  
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:orientation="vertical" android:layout_width="fill_parent"  
    android:layout_height="fill_parent">  
    <LinearLayout android:id="@+id/LinearLayout01"  
        android:layout_height="wrap_content" android:layout_width="fill_parent">  
        <ImageButton android:layout_width="wrap_content"  
            android:layout_height="wrap_content" android:id="@+id/ibtnTab1"  
            android:background="@drawable/png1298"></ImageButton>  
        <ImageButton android:layout_width="wrap_content"  
            android:layout_height="wrap_content" android:id="@+id/ibtnTab2"  
            android:background="@drawable/png1292"></ImageButton>  
    </LinearLayout>  
    <LinearLayout android:id="@+id/LinearLayout02"  
        android:layout_width="fill_parent" android:layout_height="fill_parent"></LinearLayout>  
</LinearLayout>  


Sub Activity的XML源码(listview.xml)如下:
<?xml version="1.0" encoding="utf-8"?>  
<LinearLayout android:id="@+id/LinearLayout01"  
    xmlns:android="http://schemas.android.com/apk/res/android"  
    android:layout_width="fill_parent" android:layout_height="fill_parent">  
    <ListView android:id="@+id/MyListView" android:layout_width="fill_parent"  
        android:layout_height="fill_parent">  
    </ListView>  
</LinearLayout> 


testActivityGroup.java源码如下:
package com.testActivityGroup;  
  
import android.app.ActivityGroup;  
import android.content.Intent;  
import android.os.Bundle;  
import android.view.View;  
import android.view.Window;  
import android.widget.ImageButton;  
import android.widget.LinearLayout;  
import android.widget.ListView;  
  
public class testActivityGroup extends ActivityGroup {  
    /** Called when the activity is first created. */  
    LinearLayout container;//装载sub Activity的容器  
    ImageButton ibtnTab1,ibtnTab2;  
    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.main);  
          
        container = (LinearLayout) findViewById(R.id.LinearLayout02);  
        ibtnTab1=(ImageButton)this.findViewById(R.id.ibtnTab1);  
        ibtnTab1.setOnClickListener(new ClickEvent());  
        ibtnTab2=(ImageButton)this.findViewById(R.id.ibtnTab2);  
        ibtnTab2.setOnClickListener(new ClickEvent());  
    }  
      
    class ClickEvent implements View.OnClickListener{  
  
        @Override  
        public void onClick(View v) {  
            container.removeAllViews();  
            Intent intent=new Intent(testActivityGroup.this, subActivity.class);  
            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);  
            String[] str=new String[12];  
            if(v==ibtnTab1)  
            {  
                for(int i=0;i<str.length;i++)  
                    str[i]="单选"+String.valueOf(i);  
                intent.putExtra("Name", "subActivity1");  
                intent.putExtra("Strings", str);  
                intent.putExtra("ChoiceMode", ListView.CHOICE_MODE_SINGLE);//通过参数设置列表式样  
            }  
            else if(v==ibtnTab2)  
            {  
                for(int i=0;i<str.length;i++)  
                    str[i]="复选"+String.valueOf(i);  
                intent.putExtra("Name", "subActivity2");  
                intent.putExtra("Strings", str);  
                intent.putExtra("ChoiceMode", ListView.CHOICE_MODE_MULTIPLE);//通过参数设置列表式样  
            }  
  
            Window subActivity=getLocalActivityManager().startActivity("subActivity",intent);  
            container.addView(subActivity.getDecorView());  
        }  
          
    }  
}  


subActivity.java源码如下:
package com.testActivityGroup;  
  
import android.app.Activity;  
import android.os.Bundle;  
import android.util.Log;  
import android.widget.ArrayAdapter;  
import android.widget.ListView;  
  
public class subActivity extends Activity {  
    String name;  
  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.listview);  
  
        // 读取列表内容  
        name = this.getIntent().getStringExtra("Name");  
        String[] str = this.getIntent().getStringArrayExtra("Strings");  
        int choiceMode = this.getIntent().getIntExtra("ChoiceMode",  
                ListView.CHOICE_MODE_NONE);  
  
        ListView listView = (ListView) findViewById(R.id.MyListView);  
  
        // 设置列表的式样  
        int itemID = android.R.layout.simple_list_item_1;  
        if (choiceMode == ListView.CHOICE_MODE_MULTIPLE)// 主Activity要求多选  
            itemID = android.R.layout.simple_list_item_multiple_choice;  
        else if (choiceMode == ListView.CHOICE_MODE_SINGLE)// 主Activity要求单选  
            itemID = android.R.layout.simple_list_item_single_choice;  
  
        ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this,  
                itemID, str);  
        listView.setAdapter(arrayAdapter);  
  
        listView.setChoiceMode(choiceMode);  
  
        Log.e(name, "onCreate");// 显示当前状态,onCreate与onDestroy对应  
    }  
    @Override  
    public void onDestroy() {  
        super.onDestroy();  
        Log.e(name, "onDestroy");// 显示当前状态,onCreate与onDestroy对应  
    }  
  
    @Override  
    public void onStart() {  
        super.onStart();  
        Log.e(name, "onStart");// 显示当前状态,onStart与onStop对应  
    }  
  
    @Override  
    public void onStop() {  
        super.onStop();  
        Log.e(name, "onStop");// 显示当前状态,onStart与onStop对应  
    }  
  
    @Override  
    public void onRestart() {  
        super.onRestart();  
        Log.e(name, "onRestart");  
    }  
  
    @Override  
    public void onResume() {  
        super.onResume();  
        Log.e(name, "onResume");// 显示当前状态,onPause与onResume对应  
    }  
  
    @Override  
    public void onPause() {  
        super.onResume();  
        Log.e(name, "onPause");// 显示当前状态,onPause与onResume对应  
    }  
}  
1 楼 ilzc 2011-09-15  
问下楼主用哪款屏幕录像软件可以录制emulator的动态图?

    
最新技术文章:
▪Android开发之登录验证实例教程
▪Android开发之注册登录方法示例
▪Android获取手机SIM卡运营商信息的方法
▪Android实现将已发送的短信写入短信数据库的...
▪Android发送短信功能代码
▪Android根据电话号码获得联系人头像实例代码
▪Android中GPS定位的用法实例
▪Android实现退出时关闭所有Activity的方法
▪Android实现文件的分割和组装
▪Android录音应用实例教程
▪Android双击返回键退出程序的实现方法
▪Android实现侦听电池状态显示、电量及充电动...
▪Android获取当前已连接的wifi信号强度的方法
▪Android实现动态显示或隐藏密码输入框的内容
▪根据USER-AGENT判断手机类型并跳转到相应的app...
▪Android Touch事件分发过程详解
▪Android中实现为TextView添加多个可点击的文本
▪Android程序设计之AIDL实例详解
▪Android显式启动与隐式启动Activity的区别介绍
▪Android按钮单击事件的四种常用写法总结
▪Android消息处理机制Looper和Handler详解
▪Android实现Back功能代码片段总结
▪Android实用的代码片段 常用代码总结
▪Android实现弹出键盘的方法
▪Android中通过view方式获取当前Activity的屏幕截...
▪Android提高之自定义Menu(TabMenu)实现方法
▪Android提高之多方向抽屉实现方法
▪Android提高之MediaPlayer播放网络音频的实现方法...
▪Android提高之MediaPlayer播放网络视频的实现方法...
▪Android提高之手游转电视游戏的模拟操控
 


站内导航:


特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

©2012-2021,,E-mail:www_#163.com(请将#改为@)

浙ICP备11055608号-3