【Android开发技巧】 UI开发常见问题

在做项目的时候,碰到一些常见的UI feature,在网上找了些资料,有的也不是那么完美,于是在这里简单记录下。

1. 后退(BACK按钮),退出应用程序

这个功能是当用户按下了back键时候,提示用户是否退出应用程序,点击确定,退出应用程序。网上大致的解决方案如下:捕获onKeyDown事件-->如果是KeyEvent.KEYCODE_BACK,弹出按钮-->点击确定-->退出应用程序。

大致代码如下:

public boolean onKeyDown(int keyCode, KeyEvent event) 
   {
	    if(keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_HOME)
	    {
	    	Logger.i(TAG, "key_back is pressed");
	    	CustomAlertDialog alertDialog = new CustomAlertDialog(this);
			alertDialog.setTitle(this.getResources().getString(R.string.more_alert_title))
			 .setMessage(this.getResources().getString(R.string.back_home_key))
			 .setPositiveButton(this.getResources().getString(R.string.more_alert_confirm), exitListener)
			 .setNegativeButton(this.getResources().getString(R.string.more_alert_cancel), null)
			 .show(); 
	    	
	    }
	    //case KeyEvent.KEYCODE_MENU:   
	    return super.onKeyDown(keyCode, event);
   }
   private DialogInterface.OnClickListener exitListener = new DialogInterface.OnClickListener(){
		@Override
		public void onClick(DialogInterface dialog, int which) {
			// TODO Auto-generated method stub
			//delete the account from DB;	
			Logger.i(TAG, "Exit the application");
			finish();
			exitApplication();
		}};

而对于exitApplication(),有不同的实现方式,有的有效,有的不甚理想,一般有如下几种:

a. 直接调用 System.exit(0)

---该方法最不推荐,也是android摒弃的方法。与之对应还有一个是:

android.os.Process.killProcess(android.os.Process.myPid());


b. 启用一个intent,直接跳转到系统后台。

			Intent homeIntent = new Intent(Intent.ACTION_MAIN);
			homeIntent.addCategory( Intent.CATEGORY_HOME );
			homeIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
			startActivity(homeIntent);
该方法,并没有完全实现应用程序的退出,只是退到后台,交友系统管理,在内存不够的时候会被系统杀死;

c. 比较推荐的一个方法:通过标记位,退出每一个activity。

(1)在MainActivity中定义一个标记位

public static boolean isQuit = false;
(2)在MainActivity中onCreate的时候初始化为false;
isQuit = false;
(3)捕获key事件,如果是后退键,设置该值为true。

MainActivity.isQuit = true;
			finish();

(4)在每个activity中,实现onRestart()。

@Override
	protected void onRestart()
    {
    	super.onRestart();
    	if(MainActivity.isQuit)
            finish();
    }

2. 隐藏键盘

隐藏键盘,有两种方式,可以通过代码控制,也可以通过在Manifest中配置,具体如下。

A. 代码控制。

inputManager = (InputMethodManager)this.getSystemService(Service.INPUT_METHOD_SERVICE);
inputManager.hideSoftInputFromWindow(nameEditTxt.getWindowToken(), 0);
其中nameEditTxt为键盘焦点获得的控件。

B. Activity中配置

<activity  android:name=".ui.xiaoxuntong.ProfileActivity"
                   android:windowSoftInputMode="stateHidden">
        </activity>   


在实际中,碰到的问题是A方式无效,可能原因是Activity启动时,nameEditTxt不是获得焦点的控件,具体原因待查。通过B方式,就解决这个问题。


3. ImageView的自适应问题

【问题描述】

屏幕中间有一个ImageView,填充除了顶部NavigationBar,底部toolbar之外的所有空间;当图片比ImageView小时候,放大到屏幕宽度的比例;当Image高度大于屏幕时,ImageView高度为图片高度。

【解决方案】

1. 设置ImagView的属性为

android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:scaleType="fitStart"

2. 在ImageView外面套一个scroolView

android:layout_width="fill_parent"
android:layout_height="fill_parent"


结果:图片小于屏幕,图片放置在ImageView的左上角,并不会根据宽度比例放大。这应该是跟属性fitStart有关;但如果用FitXY,在Y方向拉伸太大,图片有马赛克。又没有属性是FitX。。。

3.对图片进行等比例放大

Bitmap bmResult=null;
if((bm.getWidth()>0) && (bm.getHeight()>0))
 {
	int width = bm.getWidth();
	int height = bm.getHeight();
	Matrix matrix = new Matrix(); 
	matrix.postScale(scale, scale);
	bmResult = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, true);
}
else
{
  System.out.println();
}
return bmResult;

结果:效果达到要求,图片会根据宽度的比例,调整到屏幕的大小,在X方向填充屏幕,在Y方向,按照等比放大。

当放大后的图片高度大于屏幕时,可以通过拖动显示图片。

4. RelativeLayout背景无法改变

RelativeLayout,设置了selector,但选中的时候,没有发生变化。网上查了下,原因是RelativeLayout没有设置成Clickable=true。添加设置后,选择生效,但是带来另外一个问题OnClickListener()失效, 具体代码如下:

XML文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:id="@+id/itemContainer"
	android:orientation="horizontal" 
	android:layout_width="fill_parent" 
	android:layout_height="wrap_content"
   	android:minHeight="50dip"
   	android:clickable="true"
	style="@style/list_item_top">
	  
    <LinearLayout 
        android:layout_centerHorizontal="true" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content">
        <TextView 
            android:text="title" 
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content" 
            android:id="@+id/more_txt_top" 
            style="@style/content_page_large_text" />
    </LinearLayout>
    <ImageView 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:layout_centerVertical="true" 
        android:id="@+id/more_top_icon" 
        style="@style/list_item_chevron" 
        android:layout_alignParentRight="true"/>

</RelativeLayout> 


该XML文件对应的是一个控件,在工程中有一个MoreItemField.java的类跟它映射: 主要代码如下

public MoreItemField(Context context, AttributeSet attrs) 
{
	super(context, attrs);
	this.context = context;
	initViews(context);
}	
private void initViews(Context context) 
{
	rootView = inflate(context, R.layout.more_list_item, this);		
//		content = (TextView)rootView.findViewById(R.id.more_profile_content);
	title = (TextView)rootView.findViewById(R.id.more_txt_top);		
	img = (ImageView)rootView.findViewById(R.id.more_top_icon);	
}

this.testField = (MoreItemField)this.findViewById(R.id.more_rel_profile);
this.testField.setOnClickListener(this);

原因:当RelativeLayout设置了Clickable之后,click事件就被它获取了;虽然MoreItemField 是继承自RelativeLayout,并setOnClickListener为自己,但rootView中的RelativeLayout已经获取了click事件,导致无法监听;

当笔者在MoreItemField中添加如下代码时:

RelativeLayout root = (RelativeLayout)rootView.findViewById(R.id.itemContainer);
root.setOnClickListener(new OnClickListener(){
		@Override
		public void onClick(View v) {
				// TODO Auto-generated method stub				
			}});
事件就能响应到了。


但由于处理响应事件的Listener应该在调用控件的地方,这种方式影响了控件本身的灵活性。就像Button,我们不会把响应Button的行为放到Button类中,而是放在调用Button的类中。

那又如何在让ReleativeLayout能响应click事件,又同时适应Selector呢?

解决方案2:

A. 将XML文件中的style移除,style的属性在调用它的地方设置。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:background="#cccccc"
    android:layout_height="fill_parent">
	<!-- the top bar-->
   	<include layout="@layout/navgation_bar"
        android:id="@+id/navbar"
       	android:layout_width="match_parent"
        android:layout_height="49dp"/> 
	<!-- the logout bar-->
	<com.huahai.xxt.ui.more.MoreItemField
        android:id="@+id/more_rel_logout"
        style="@style/list_item_top"
        android:layout_marginTop="15dp"
        android:layout_marginRight="15dp"
        android:layout_marginLeft="15dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/navbar">
    </com.huahai.xxt.ui.more.MoreItemField>   
</RelativeLayout>

4. 键盘无法自动弹出
有个需求是:在屏幕一启动的时候,焦点在EditText,然后自动弹出数字键盘。

在设置了EditText获取焦点,其输入类型为数字之后,发下键盘无法自动弹出。

网上查了下,最终可行的解决方案有:

A. 在Manifest中的activity中添加属性

android:windowSoftInputMode="adjustResize"

B. 在View中设置一个Timer或handler,设置键盘的弹出方式:

Timer timer = new Timer();
timer.schedule(new TimerTask() {
    	@Override
    		public void run() {
    		InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
    		imm.showSoftInput(edt_schoolnum, InputMethodManager.RESULT_SHOWN);
    		imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY);
    		}
    	}, 300);

其中,edt_schoolnum为对应的EditText,同时在调用该timer之前,edt_schoolnum已经获取了焦点。

edt_schoolnum.requestFocus();




你可能感兴趣的:(【Android开发技巧】 UI开发常见问题)