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的交互相关的详细信息,可自行查询相关文档。

浙公网安备 33010602011771号