Unity 读取android自定义控件及布局文件

在unity中开发游戏时,难免会用到一些android的原生功能,另外在调用第三方sdk的过程中也会经常有类似的需求。但是在unity中调用android jar包中的布局文件或者图片等资源时,由于unity的重新打包,生成了新的R文件,导致原来jar包中通过R读取的资源文件都找不到。所以就必须修改读取方式来达到正常读取的需求。

1、创建一个自定义控件。

1)布局文件如下:

如图:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <ImageView
        android:id="@+id/imageView1"
        android:layout_gravity="center"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/myview" />

    <EditText
        android:id="@+id/editText1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ems="20"
        android:inputType="textPersonName" >

        <requestFocus />
    </EditText>

</LinearLayout>

2)代码中读取布局文件,获得控件实例。

public class MyView extends LinearLayout{
    private ImageView img;
    private EditText edt;
    public MyView(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
    }

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
        LayoutInflater inflater=(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        /*
         *此种做法是无效的,空引用
        View v = inflater.inflate(R.layout.mybtnlayout, null);
        img = (ImageView)v.findViewById(R.id.imageView1);
        edt = (EditText)v.findViewById(R.id.editText1);
        */
        
        /**
         *有效的做法
         */
        View v = inflater.inflate(MResource.getIdByName(context, "layout", "mybtnlayout"), this);
        img=(ImageView)v.findViewById(MResource.getIdByName(context, "id", "imageView1"));
        edt=(EditText)v.findViewById(MResource.getIdByName(context, "id", "editText1"));
    }
     
    /**
     * 设置图片资源
     */ 
    public void setImageResource(int resId) { 
        img.setImageResource(resId); 
    } 
   
    /**
     * 设置显示的文字
     */ 
    public void setTextViewText(String text) { 
        edt.setText(text); 
    } 
}

3)重要:资源文件读取方式:

package com.example.myview;

import java.io.IOException;
import java.io.InputStream;

import android.content.Context;
import android.content.res.AssetManager;
import android.graphics.drawable.Drawable;

public class MResource {
    /**
     * 根据资源的名字获取其ID值
     * 
     * @author mining
     * 
     */
    public static int getIdByName(Context context, String className, String name) {
        //此处的包名不能通过context获取,因为在unity中这样获取到的是unity额外设定的包名,不是jar包里面的包名
        String packageName = "com.example.updategameapp";
        Class r = null;
        int id = 0;
        try {
            r = Class.forName(packageName + ".R");

            Class[] classes = r.getClasses();
            Class desireClass = null;

            for (int i = 0; i < classes.length; ++i) {
                if (classes[i].getName().split("\\$")[1].equals(className)) {
                    desireClass = classes[i];
                    break;
                }
            }

            if (desireClass != null)
                id = desireClass.getField(name).getInt(desireClass);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

        return id;
    }

    public static int[] getIdsByName(Context context, String className,
            String name) {
        String packageName = context.getPackageName();
        Class r = null;
        int[] ids = null;
        try {
            r = Class.forName(packageName + ".R");

            Class[] classes = r.getClasses();
            Class desireClass = null;

            for (int i = 0; i < classes.length; ++i) {
                if (classes[i].getName().split("\\$")[1].equals(className)) {
                    desireClass = classes[i];
                    break;
                }
            }

            if ((desireClass != null)
                    && (desireClass.getField(name).get(desireClass) != null)
                    && (desireClass.getField(name).get(desireClass).getClass()
                            .isArray()))
                ids = (int[]) desireClass.getField(name).get(desireClass);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

        return ids;
    }

    public static Drawable getDrawableFromAssets(Context context,
            String imageFileName) {
        Drawable result = null;
        AssetManager assetManager = context.getAssets();
        InputStream is = null;
        try {
            is = assetManager.open(imageFileName);
            result = Drawable.createFromStream(is, null);
            is.close();
            is = null;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }
}

 

4)将自定义布局文件打成jar包供下面的工程调用。打jar包时只需选中src和gen目录。

如图:

2、 在android项目中引用自定义控件。

如图:

1)创建一个新的工程,将1中生成好的自定义控件jar包放置到libs目录下,并添加到buildpath。

2)将自定义控件中用到的布局文件和图片资源放置到android项目中相应的目录下。

3)将自定义控件添加到新的布局文件中:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/dialog_view" 
    android:orientation="vertical"
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content"
    android:minHeight="60dp"
    android:minWidth="180dp"
    android:gravity="center"
    android:padding="10dp"
    android:background="@drawable/loading_bg">

    <ImageView 
        android:id="@+id/img"
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:src="@drawable/publicloading"
        />
    
    <TextView 
        android:id="@+id/tipTextView"
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:text="数据加载中……" />
    
     <com.example.myview.MyView
        android:id="@+id/myView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" >
    </com.example.myview.MyView>
</LinearLayout>

 

4)在新的项目中读取1中的自定义控件方法如下:

/**
     * 创建自定义的progressDialog
     * @param context
     * @param msg
     * @return
     */
    public Dialog createLoadingDialog(Context context, String msg) {

        LayoutInflater inflater = LayoutInflater.from(context);
        int layoutId = MResource.getIdByName(context, "layout", "loading_dialog");
        View v = inflater.inflate(layoutId, null);// 得到加载view
        LinearLayout layout = (LinearLayout) v.findViewById(MResource.getIdByName(context, "id", "dialog_view"));// 加载布局
        // main.xml中的ImageView
        ImageView spaceshipImage = (ImageView) v.findViewById(MResource.getIdByName(context, "id", "img"));
        TextView tipTextView = (TextView) v.findViewById(MResource.getIdByName(context, "id", "tipTextView"));// 提示文字
        tipTextView.setText(msg);// 设置加载信息
        // 加载动画
        Animation hyperspaceJumpAnimation = AnimationUtils.loadAnimation(
                context,MResource.getIdByName(context, "anim", "loading_animation"));
        // 使用ImageView显示动画
        spaceshipImage.startAnimation(hyperspaceJumpAnimation);
        
        MyView myView = (MyView)v.findViewById(MResource.getIdByName(context, "id", "myView1"));
        myView.setTextViewText("Good!");
        Dialog loadingDialog = new Dialog(context,MResource.getIdByName(context, "style", "loading_dialog"));// 创建自定义样式dialog

        loadingDialog.setCancelable(false);// 不可以用“返回键”取消
        loadingDialog.setContentView(layout, new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.FILL_PARENT,
                LinearLayout.LayoutParams.FILL_PARENT));// 设置布局
        return loadingDialog;

    }

 

5)创建一个Activity,用createLoadingDialog方法测试下生成的控件:

public class MainActivity extends Activity {//UnityPlayerActivity
     @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Dialog dlg = createLoadingDialog(this, "my custorm dialog");
        dlg.show();
    }
}

6)可以正常运行后,修改MainActivity使其继承自UnityPlayerActivity,然后创建供unity调用的方法。

public class MainActivity extends UnityPlayerActivity {

    public void ShowDialog(final Activity act){
        act.runOnUiThread(new Runnable() {
            
            @Override
            public void run() {
                // TODO Auto-generated method stub
                Dialog dlg = createLoadingDialog(act, "fuck you...");
                dlg.show();
            }
        });
    }

    /**
     * 创建自定义的progressDialog
     * @param context
     * @param msg
     * @return
     */
    public Dialog createLoadingDialog(Context context, String msg) {

        LayoutInflater inflater = LayoutInflater.from(context);
        int layoutId = MResource.getIdByName(context, "layout", "loading_dialog");
        View v = inflater.inflate(layoutId, null);// 得到加载view
        LinearLayout layout = (LinearLayout) v.findViewById(MResource.getIdByName(context, "id", "dialog_view"));// 加载布局
        // main.xml中的ImageView
        ImageView spaceshipImage = (ImageView) v.findViewById(MResource.getIdByName(context, "id", "img"));
        TextView tipTextView = (TextView) v.findViewById(MResource.getIdByName(context, "id", "tipTextView"));// 提示文字
        tipTextView.setText(msg);// 设置加载信息
        // 加载动画
        Animation hyperspaceJumpAnimation = AnimationUtils.loadAnimation(
                context,MResource.getIdByName(context, "anim", "loading_animation"));
        // 使用ImageView显示动画
        spaceshipImage.startAnimation(hyperspaceJumpAnimation);
        
        MyView myView = (MyView)v.findViewById(MResource.getIdByName(context, "id", "myView1"));
        myView.setTextViewText("Good!");
        Dialog loadingDialog = new Dialog(context,MResource.getIdByName(context, "style", "loading_dialog"));// 创建自定义样式dialog

        loadingDialog.setCancelable(false);// 不可以用“返回键”取消
        loadingDialog.setContentView(layout, new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.FILL_PARENT,
                LinearLayout.LayoutParams.FILL_PARENT));// 设置布局
        return loadingDialog;
    }

}

3、将2中的android项目导出jar包供unity调用。

1)导出jar包,仍然选中arc和gen目录。导出的jar包放置到unity中Plugins/Android/bin/目录下。

2)将res目录复制到unity中的Plugins/Android/目录下。

3)将AndroidManifest文件复制到Plugins/Android/目录下。

4)在unity中调用ShowDialog方法,即可显示出一个完整的对话框。

 

PS:本篇blog重点不在于unity如何调用android方法,而是如果修改android工程中资源以及布局文件的读取方式,所以unity与android的交互相关的详细信息,可自行查询相关文档。

 

posted @ 2014-11-04 15:48  CrazyCoder361  阅读(2311)  评论(0)    收藏  举报