没有花太多的时间去研究,所以效果一般,不是很满意。烟雾是由屏幕右方飘向左方的。如果换为竖直方向感觉更像蒸汽效果。
不多说了,放代码:
@Override protected Scene onCreateScene() { final Scene scene = new Scene(); Sprite background = new Sprite(0, 0, backgroundTextureRegion, getVertexBufferObjectManager()); scene.attachChild(background); RectangleParticleEmitter emitter = new RectangleParticleEmitter(CAMERA_WIDTH, CAMERA_HEIGHT / 2, 1, CAMERA_HEIGHT); final SpriteParticleSystem particleSystem = new SpriteParticleSystem(emitter, 10, 90, 360, mParticleTextureRegion, getVertexBufferObjectManager()); particleSystem.addParticleInitializer(new ColorParticleInitializer<Sprite>(0.45f, 0.45f, 0.45f)); particleSystem.addParticleInitializer(new AlphaParticleInitializer<Sprite>(0)); particleSystem.addParticleInitializer(new BlendFunctionParticleInitializer<Sprite>(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE)); particleSystem.addParticleInitializer(new VelocityParticleInitializer<Sprite>(-50, -5, -5, 5)); particleSystem.addParticleInitializer(new RotationParticleInitializer<Sprite>(0.0f, 360.0f)); particleSystem.addParticleInitializer(new ExpireParticleInitializer<Sprite>(9)); particleSystem.addParticleModifier(new ScaleParticleModifier<Sprite>(0, 1, 1.0f, 3.0f)); particleSystem.addParticleModifier(new ColorParticleModifier<Sprite>(0, 2, 0, 0.45f, 0, 0.45f, 0, 0.45f)); particleSystem.addParticleModifier(new ColorParticleModifier<Sprite>(3, 5, 0.45f, 0, 0.45f, 0, 0.45f, 0)); particleSystem.addParticleModifier(new ColorParticleModifier<Sprite>(6, 9, 0, 0.45f, 0, 0.45f, 0, 0.45f)); particleSystem.addParticleModifier(new AlphaParticleModifier<Sprite>(0, 1, 0, 0.25f)); particleSystem.addParticleModifier(new AlphaParticleModifier<Sprite>(2, 5, 0.25f, 0)); particleSystem.addParticleModifier(new AlphaParticleModifier<Sprite>(6, 7, 0.25f, 0)); particleSystem.addParticleModifier(new AlphaParticleModifier<Sprite>(8, 9, 0.25f, 0)); scene.attachChild(particleSystem); scene.setOnSceneTouchListener(new IOnSceneTouchListener() { public boolean onSceneTouchEvent(Scene pScene, TouchEvent pSceneTouchEvent) { if (pSceneTouchEvent.isActionUp()) { particleSystem.setParticlesSpawnEnabled(false); } return false; } }); return scene; }粒子效果使用的图片还是AndEngine例子中的图片。
目前总结在ui层来说,可能有些人会认为这没有技术含量,其实我个人认为不然。ui层写的好坏会影响整个项目后期写逻辑层的处理,重要的是用户体验。比如说,这几个星期我做的一个项目,一个功能是绑定设备和解除绑定设备,我用的是通过addview和remove的方法来添加布局和擦除布局的,开始考虑这样写的目的是为了减少使用Activity,但是其实这样带来的用户体验很不好(后面同事给了些建议)。前期ui都是我一个人写的(后期才有同事加入这个项目,所以没人讨论),由于一个人写,在一些方面想法不是很好。后面同事花了一下午的时间对整个项目布局稍微修改了下。写ui的时候一定要主要适配问题,尽量不要写死布局。因为android的手机大小不一,不像iphone那样。
关于自定义控件以及自定义属性的文章,可以查看 Android高手进阶教程(四)之----Android 中自定义属性(attr.xml,TypedArray)的使用!。本文主要在其基础之上结合实际开发当中遇到的问题,举例分析一下在使用TypedArray.getDimension时应当注意的问题。
一、主要代码以及不同手机显示图片主要显示代码main.xml关键代码:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:test="http://schemas.android.com/apk/res/com.yang" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" android:background="@color/background"> <TextView android:layout_height="wrap_content" android:layout_width="wrap_content" android:textColor="@android:color/black" android:textSize="18sp" android:text="@string/shiyan"/> <com.yang.widget.TextViewAndSpaner android:layout_width="fill_parent" android:layout_height="wrap_content" test:item_content_text="@string/shiyan" test:item_content_textsize="18sp" test:item_content_textcolor="@android:color/black" test:item_option_prompt="@string/please_select" test:item_option_values="@array/tureorfalse" /> </LinearLayout>text_spaner_view.xml代码:
<?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" > <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1.33" android:orientation="vertical" > <TextView android:id="@+id/item_content" android:layout_width="240dip" android:layout_height="wrap_content" android:singleLine="false" android:textSize="15sp" /> <TextView android:id="@+id/item_remark_str" android:layout_width="240dip" android:layout_height="wrap_content" android:singleLine="false" android:textSize="10sp" android:visibility="gone"/> </LinearLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:orientation="vertical" > <Button android:id="@+id/item_option" android:layout_width="80dip" android:layout_height="45dip" android:text="@string/please_select" android:textSize="13sp" /> <TextView android:id="@+id/item_option_ps" android:layout_width="wrap_content" android:layout_height="wrap_content" android:singleLine="false" android:textSize="10sp" android:layout_gravity="center" android:visibility="gone" /> <Button android:id="@+id/item_remark" android:layout_width="80dip" android:layout_height="30dip" android:text="备注" android:textSize="10sp" android:visibility="gone" /> </LinearLayout> </LinearLayout> <View android:layout_width="fill_parent" android:layout_height="1dp" android:background="@android:color/white" /> </LinearLayout>TextViewAndSpaner.java
package com.yang.widget; import com.yang.R; import com.yang.utils.Logger; import android.app.AlertDialog; import android.app.AlertDialog.Builder; import android.content.Context; import android.content.DialogInterface; import android.content.res.TypedArray; import android.text.TextUtils; import android.util.AttributeSet; import android.util.TypedValue; import android.view.LayoutInflater; import android.view.View; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.TextView; public class TextViewAndSpaner extends LinearLayout { private TextView item_content; private Button item_remark; // 1、使用startActivityforResult或者 // 2、设置Intent的Type属性 // 但是使用后者时需要将原先的Activity传过来,在TextViewAndSpaner中添加代码。 // 同时,要开启Activity当中设置判断条件。开发复杂。因此使用前者。 private TextView item_remark_str; private Button item_option; public Button getItem_option() { return item_option; } public void setItem_option(Button item_option) { this.item_option = item_option; } private TextView item_option_ps; private Context mContext; private boolean isopposites; /** * 默认构造函数 */ public TextViewAndSpaner(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub mContext = context; LayoutInflater.from(context).inflate(R.layout.text_spaner_view, this, true); item_content = (TextView) findViewById(R.id.item_content); item_remark = (Button) findViewById(R.id.item_remark); item_option = (Button) findViewById(R.id.item_option); item_remark_str = (TextView) findViewById(R.id.item_remark_str); item_option_ps = (TextView) findViewById(R.id.item_option_ps); TypedArray typeArray = context.obtainStyledAttributes(attrs, R.styleable.TextViewAndSpaner); setItemContext(typeArray); setItemRemark(typeArray); // 设置相关的点击选项 setOption(typeArray); setRemark(typeArray); // 回收 typeArray.recycle(); } private void setRemark(TypedArray typeArray) { // TODO Auto-generated method stub boolean remarkFlag = typeArray.getBoolean( R.styleable.TextViewAndSpaner_is_remark_enable, false); if (remarkFlag) { item_remark.setVisibility(View.VISIBLE); item_remark.setOnClickListener(new OnClickListener() { public void onClick(View v) { // TODO Auto-generated method stub remarkDialog(); } }); } } private void setItemContext(TypedArray typeArray) { int contentColor = typeArray.getColor( R.styleable.TextViewAndSpaner_item_content_textcolor, 0XFFFFFFFF); item_content.setTextColor(contentColor); Logger.d("getDimensionPixelOffset" + typeArray .getDimensionPixelOffset( R.styleable.TextViewAndSpaner_item_content_textsize, 15)); Logger.d("getDimensionPixelSize" + typeArray .getDimensionPixelSize( R.styleable.TextViewAndSpaner_item_content_textsize, 15)); Logger.d("getLayoutDimension" + typeArray .getLayoutDimension( R.styleable.TextViewAndSpaner_item_content_textsize, 15)); float contentSize = typeArray.getDimension( R.styleable.TextViewAndSpaner_item_content_textsize, 15); Logger.d("contentSize is " + contentSize); item_content.setTextSize(TypedValue.COMPLEX_UNIT_SP, contentSize); String contentStr = typeArray .getString(R.styleable.TextViewAndSpaner_item_content_text); item_content.setText(contentStr); } private void setItemRemark(TypedArray typeArray) { boolean remarkFlag = typeArray.getBoolean( R.styleable.TextViewAndSpaner_is_remark_enable, false); if (remarkFlag) { int remarkColor = typeArray.getColor( R.styleable.TextViewAndSpaner_item_remark_textcolor, 0XFFFFFFFF); item_remark_str.setTextColor(remarkColor); float remarkSize = typeArray.getDimension( R.styleable.TextViewAndSpaner_item_remark_textsize, 12); item_remark_str.setTextSize(remarkSize); } } private void setOption(TypedArray typeArray) { isopposites = typeArray.getBoolean( R.styleable.TextViewAndSpaner_is_item_option_opposites, false); boolean isResult = typeArray.getBoolean( R.styleable.TextViewAndSpaner_is_query_result, false); if (isResult) item_option.setEnabled(false); else { final CharSequence[] values = typeArray .getTextArray(R.styleable.TextViewAndSpaner_item_option_values); final String when_to_show_dialogue_item = typeArray .getString(R.styleable.TextViewAndSpaner_when_to_show_dialogue_item); final String prompt = typeArray .getString(R.styleable.TextViewAndSpaner_item_option_prompt); final ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>( mContext, android.R.layout.simple_spinner_dropdown_item, values); final CharSequence[] attrs = typeArray .getTextArray(R.styleable.TextViewAndSpaner_item_option_selected_dialogue_item); final String promptStr = typeArray .getString(R.styleable.TextViewAndSpaner_prompt_of_dialog); item_option.setOnClickListener(new OnClickListener() { public void onClick(View v) { // TODO Auto-generated method stub new AlertDialog.Builder(mContext) .setTitle(prompt) .setAdapter(adapter, new DialogInterface.OnClickListener() { public void onClick( DialogInterface dialog, int which) { String selectedValue = values[which] .toString(); item_option.setText(values[which]); if (selectedValue .equals(when_to_show_dialogue_item)) { showDiag(attrs, promptStr); } else { item_option_ps.setText(null); item_option_ps .setVisibility(View.GONE); } dialog.dismiss(); } }).create().show(); } }); } } private void showDiag(final CharSequence[] attrs, String promptStr) { AlertDialog.Builder builder = new Builder(mContext); builder.setTitle("请选择……"); builder.setPositiveButton(attrs[0], new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { // TODO Auto-generated method stub item_option_ps.setVisibility(View.VISIBLE); item_option_ps.setText(attrs[0]); } }); builder.setNegativeButton(attrs[1], new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { // TODO Auto-generated method stub item_option_ps.setVisibility(View.VISIBLE); item_option_ps.setText(attrs[1]); } }); builder.setIcon(android.R.drawable.ic_dialog_info); builder.setMessage(promptStr); builder.show(); } private void remarkDialog() { final EditText remark_text = new EditText(mContext); String oldRemark_text = (String) item_remark_str.getText(); if (!TextUtils.isEmpty(oldRemark_text)) { remark_text.setText(oldRemark_text); } new AlertDialog.Builder(mContext).setTitle("添加备注") .setIcon(android.R.drawable.ic_dialog_info) .setView(remark_text) .setPositiveButton("确定", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { // TODO Auto-generated method stub item_remark_str.setVisibility(View.VISIBLE); item_remark_str.setText(remark_text.getText() .toString().trim()); } }).setNegativeButton("取消", null).show(); } public String getKeyValue() { String optionResult = (String) item_option.getText(); if (isopposites) { // 如果是反义,则在值后面加空格 return optionResult + " "; } return optionResult; } public void setOptionDefaultValue() { item_option.setText(""); } public String getRemarkValue() { String psStr = (String) item_option_ps.getText(); String remarkStr = (String) item_remark_str.getText(); if (psStr != null && remarkStr != null && !TextUtils.isEmpty(psStr.trim()) && !TextUtils.isEmpty(remarkStr.trim())) { return item_content.getText() + "的备注:" + psStr + "," + remarkStr; } if (psStr != null && !TextUtils.isEmpty(psStr.trim())) { return item_content.getText() + "的备注:" + psStr; } if (remarkStr != null && !TextUtils.isEmpty(remarkStr.trim())) { return item_content.getText() + "的备注:" + remarkStr; } return null; } }MainActivity.java
package com.yang; import android.app.Activity; import android.os.Bundle; public class MainActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } }
例子图示如下:
摩托罗拉xt910
中兴 v880
中兴 n760
华为c8500
我们看到根据屏幕大小的不同,两行文字中下行文字的大小也随之改变,其中摩托罗拉xt910和中兴 v880下面字体的都比上面字体大,而中兴 n760下面字体与上面字体大小是相同的,而华为c8500下面字体比上面字体小。我们再来看看main.xml代码:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:test="http://schemas.android.com/apk/res/com.yang" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" android:background="@color/background"> <TextView android:layout_height="wrap_content" android:layout_width="wrap_content" android:textColor="@android:color/black" android:textSize="18sp" android:text="@string/shiyan"/> <com.yang.widget.TextViewAndSpaner android:layout_width="fill_parent" android:layout_height="wrap_content" test:item_content_text="@string/shiyan" test:item_content_textsize="18sp" test:item_content_textcolor="@android:color/black" test:item_option_prompt="@string/please_select" test:item_option_values="@array/tureorfalse" /> </LinearLayout>TextView设置的字体大小为18sp,而com.yang.widget.TextViewAndSpaner设置的字体大小也为18sp
com.yang.widget.TextViewAndSpaner读取字体大小的代码如下:
float contentSize = typeArray.getDimension( R.styleable.TextViewAndSpaner_item_content_textsize, 15); Logger.d("contentSize is " + contentSize);
四个手机打印出自定义属性来的字体大小为:
摩托罗拉xt910 09-08 15:07:00.685: D/CustomWidget(4937): contentSize is 27.0 中兴 v880 09-08 15:15:04.685: D/CustomWidget(4937): contentSize is 27.0 中兴 n760 09-08 15:05:15.640: D/CustomWidget(31487): contentSize is 18.0 华为c8500 09-08 15:22:48.565: D/CustomWidget(2018): contentSize is 13.5三、注意事项
以上我们看到使用自定义属性的
typeArray.getDimension
是不靠谱的,字体的大小会根据不同屏幕的分辨率大小而改变字体的大小。我们再来看看关于getDimension
public float getDimension (int id)Retrieve a dimensional for a particular resource ID. Unit conversions are based on the current DisplayMetrics associated with the resources.
- Resource dimension value multiplied by the appropriate metric.
- getDimensionPixelOffset(int)
- getDimensionPixelSize(int)
单位的转换是基于当前资源显示分比率的。
因此我们要慎重使用getDimension定义的属性,不然我们的应用部署到不同的应用上,原先非常美丽的效果,会变得面目全非。
四、使用时,默认将字体大小设定好,而在xml配置文件当中删除关于字体大小的设置。如
删除main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:test="http://schemas.android.com/apk/res/com.yang" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" android:background="@color/background"> <TextView android:layout_height="wrap_content" android:layout_width="wrap_content" android:textColor="@android:color/black" android:textSize="18sp" android:text="@string/shiyan"/> <com.yang.widget.TextViewAndSpaner android:layout_width="fill_parent" android:layout_height="wrap_content" test:item_content_text="@string/shiyan" test:item_content_textsize="18sp" test:item_content_textcolor="@android:color/black" test:item_option_prompt="@string/please_select" test:item_option_values="@array/tureorfalse" /> </LinearLayout>中的
test:item_content_textsize="18sp"配置,使其变成:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:test="http://schemas.android.com/apk/res/com.yang" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" android:background="@color/background"> <TextView android:layout_height="wrap_content" android:layout_width="wrap_content" android:textColor="@android:color/black" android:textSize="18sp" android:text="@string/shiyan"/> <com.yang.widget.TextViewAndSpaner android:layout_width="fill_parent" android:layout_height="wrap_content" test:item_content_text="@string/shiyan" test:item_content_textcolor="@android:color/black" test:item_option_prompt="@string/please_select" test:item_option_values="@array/tureorfalse" /> </LinearLayout>
同时在读取自定义属性的java代码中设置好自己想要的字体大小即可,如下:
float contentSize = typeArray.getDimension( R.styleable.TextViewAndSpaner_item_content_textsize, 15);