今天在使用DatePicker时真是被这个控件恶心到了。。。
1.月份的日期不会跟着月份或者年份变动
2.没有闰年的判断
好吧,看来只能自己判断了:
新建一个layout:
choise_date.xml



	

然后新建个类,继承自LinearLayout用来显示在弹出的对话框中:

package com.zhang.test.views;

import java.util.Calendar;
import java.util.GregorianCalendar;

import com.zhang.test.R;

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.DatePicker;
import android.widget.LinearLayout;
import android.widget.DatePicker.OnDateChangedListener;

public class DatePickerDialogView extends LinearLayout {

	private static final String TAG = "DatePickerDialogView";
	private static Context mContext;

	private DatePicker mDatePicker;

	private Calendar mC;

	public DatePickerDialogView(Context context, AttributeSet attrs) {
		super(context, attrs);
		initialize(context);
	}

	public DatePickerDialogView(Context context) {
		super(context);
		initialize(context);
	}

	private void initialize(Context context) {
		mC = Calendar.getInstance();

		mContext = context;
		View view = LayoutInflater.from(mContext).inflate(R.layout.choise_date, null);
		mDatePicker = (DatePicker) view.findViewById(R.id.datepicker_date);
		mDatePicker.init(mC.get(Calendar.YEAR), mC.get(Calendar.MONTH), mC.get(Calendar.DAY_OF_MONTH), onDateChangedListener);

		addView(view);
	}

	/**
	 * 日期更改时监听事件
	 */
	private OnDateChangedListener onDateChangedListener = new OnDateChangedListener() {

		@Override
		public void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth) {

			//判断闰年
			boolean mIsLeapYear = ((GregorianCalendar)mC).isLeapYear(year);

			if(mIsLeapYear && monthOfYear == 1 && dayOfMonth > 29) {
				//闰年,2月,天数大于29天
				view.init(year, monthOfYear, 29, onDateChangedListener);
			} else if(mIsLeapYear && monthOfYear == 1) {
				//由于控件bug,只要是闰年,同时月份是2月份,就去init控件
				view.init(year, monthOfYear, dayOfMonth, onDateChangedListener);
			} else if(!mIsLeapYear && monthOfYear == 1 && dayOfMonth > 28) {
				//平年,2月,天数大于28天
				view.init(year, monthOfYear, 28, onDateChangedListener);
			} else if(!mIsLeapYear && (monthOfYear != 1) && ((monthOfYear + 1) % 2 == 0) && (dayOfMonth > 30)) {
				//平年,除2月外,可以被2整出的月份(4,6,8,10,12),月份总天数大于30天
				view.init(year, monthOfYear, 30, onDateChangedListener);
			} else if((monthOfYear != 1) && ((monthOfYear + 1) % 2 == 0) && (dayOfMonth > 30)) {
				//除2月外,可以被2整出的月份(4,6,8,10,12),月份总天数大于30天
				view.init(year, monthOfYear, 30, onDateChangedListener);
			}
		}
	};

	/**
	 * 获得日期
	 * @return String
	 */
	public String getDate() {
		return mDatePicker.getYear() + "-" + (mDatePicker.getMonth() + 1) + "-" + mDatePicker.getDayOfMonth();
	}

}

主要是使用DatePicker的init方法的对控件变更时进行监听。

最后是activity:

package com.zhang.test;

import java.util.Calendar;

import com.zhang.test.views.DatePickerDialogView;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;

public class MainActivity extends Activity {

	private static final String TAG = "MainActivity";
	private static Context mContext;

	private Button btnChange;
	private EditText dateEditText;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        mContext = this;
        btnChange = (Button) findViewById(R.id.button_change);
        dateEditText = (EditText) findViewById(R.id.EditText01);

        btnChange.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				AlertDialog.Builder a = new Builder(mContext);
				final DatePickerDialogView dateView = new DatePickerDialogView(mContext);
				a.setTitle("选择日期");
				a.setView(dateView);
				a.setPositiveButton("确定",new DialogInterface.OnClickListener() {

					@Override
					public void onClick(DialogInterface dialog, int which) {
						dateEditText.setText(dateView.getDate());
					}
				});
				a.show();
			}
        });
        Calendar c = Calendar.getInstance();
        dateEditText.setText(c.get(Calendar.YEAR) + "-" + (c.get(Calendar.MONTH) + 1) + "-" + c.get(Calendar.DAY_OF_MONTH));
    }
}

通过AlertDialog.Builder弹出一个对话框,再通过对话框的setView方法把刚才自定义的Veiw放进去。

执行结果:

代码:
TestDataPicker

android中自定义ListView 知道怎样自定义ListView后,也许在开发过程中会遇到这样的需求:
一个Activity,其中不只有ListView一个控件,还有其他的TextView、ImageView、Button等等很多控件,这样很可能会占据屏幕很大一部分,要知道手机的屏幕只有480像素,通常的想法是给这个Activity加上一个ScrollView,让其有滚动条,但是会发现ListView的高度不是随着内容而自动填充的。那么我们可以使用ListView的addHeaderView以及addFooterView 为ListView增加上下的头和尾,这样就可以让ListView填充到整个屏幕。

新建一个Layout:
demo_list_item_header_view.xml:



	

然后新建一个类,继承自LinearLayout用来显示上面的Layout:
DemoListHeaderView.java

package com.zhang.test.view;

import com.zhang.test.R;

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;

public class DemoListHeaderView extends LinearLayout {

	private static final String TAG = "DemoListHeaderView";
	private Context context;
	private TextView textView;

	public DemoListHeaderView(Context context, AttributeSet attrs) {
		super(context, attrs);
		initialize(context);
	}

	public DemoListHeaderView(Context context) {
		super(context);
		initialize(context);
	}

	private void initialize(Context context) {
		this.context = context;
		View view = LayoutInflater.from(this.context).inflate(R.layout.demo_list_item_header_view, null);
		textView = (TextView) view.findViewById(R.id.headerTextView);
		addView(view);
	}

	public void setTextView(String text) {
		textView.setText(text);
	}
}

之后在ListView设置setAdapter之前,一定要在setAdapter之前
加上代码:


        DemoListHeaderView headerView = new DemoListHeaderView(context);
        headerView.setTextView("Header : ");
        listView.addHeaderView(headerView);

        DemoListHeaderView footerView = new DemoListHeaderView(context);
        footerView.setTextView("Footer : ");
        listView.addFooterView(footerView);

全部(根据上一篇文章修改)

package com.zhang.test;

import java.util.ArrayList;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.widget.ListView;

import com.zhang.test.view.DemoListHeaderView;
import com.zhang.test.view.DemoListItemView;
import com.zhang.test.view.adapter.DemoListAdapter;

public class demoActivity extends Activity {

	private static final String TAG = "demoActivity";
	private Context context;
	private ListView listView;
	private ArrayList datas;
	private DemoListAdapter datasAdapter;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        context = this;
        listView = (ListView) findViewById(R.id.listView);
        datas = new ArrayList();
        loadData();
        datasAdapter = new DemoListAdapter(context, datas);

        DemoListHeaderView headerView = new DemoListHeaderView(context);
        headerView.setTextView("Header : ");
        listView.addHeaderView(headerView);

        DemoListHeaderView footerView = new DemoListHeaderView(context);
        footerView.setTextView("Footer : ");
        listView.addFooterView(footerView);

        listView.setAdapter(datasAdapter);
    }

    private void loadData() {
    	DemoListItemView.Data d;
    	for(int i=0; i<10; i++) {
    		d = new DemoListItemView.Data();
    		d.topText = "测试top";
    		d.bottomText = "测试bottom";
    		datas.add(d);
    	}
    }
}

运行结果:

代码:
DemoListView

研究了下ListView的自定义item view:
首先,建立一个layout:



	
	

显示结果如下:

*我在这里新建了一个包,用于存放所有view:com.zhang.test.view
然后新建一个类:DemoListItemView 继承自LinearLayout,如果自定义view使用的是其他Layout,那么就继承自其他的Layout,比如RelativeLayout等等。

写入代码:

package com.zhang.test.view;

import java.util.zip.Inflater;

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.zhang.test.R;

public class DemoListItemView extends LinearLayout {

	private static final String TAG = "DemoListItemView";
	private Context context;
	private TextView topTextView, bottomTextView;

	public DemoListItemView(Context context, AttributeSet attrs) {
		super(context, attrs);
		initialize(context);
	}

	public DemoListItemView(Context context) {
		super(context);
		initialize(context);
	}

	private void initialize(Context context) {
		this.context = context;
		View view = LayoutInflater.from(this.context).inflate(R.layout.demo_list_item_view, null);
		topTextView = (TextView) view.findViewById(R.id.topTextView);
		bottomTextView = (TextView) view.findViewById(R.id.bottomTextView);
		addView(view);
	}

	public void updateView(Data d) {
		topTextView.setText(d.topText);
		bottomTextView.setText(d.bottomText);
	}

	/**
	 * 自定义数据类型,用于显示当前item所需要的数据
	 * @author zhang
	 *
	 */
	public static final class Data {

		public String topText;
		public String bottomText;

		public Data() { }

		public Data(Data d) {
			topText = d.topText;
			bottomText = d.bottomText;
		}
	}
}

这里面有个内部类:Data。
通常每一个ListView的item都会显示不同内容,那么把每一个item要显示的内容封装成一个类方便赋值。

接下来是Adapter,新建一个类:DemoListAdapter 继承自BaseAdapter。
我在这里也建立了一个包,用于存放所有adapter:com.zhang.test.adapter

package com.zhang.test.view.adapter;

import java.util.ArrayList;

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;

import com.zhang.test.view.DemoListItemView;

public class DemoListAdapter extends BaseAdapter {

	private static final String TAG = "DemoListAdapter";
	private Context context;
	private ArrayList datas;

	public DemoListAdapter(Context context) {
		this.context = context;
	}

	public DemoListAdapter(Context context, ArrayList datas) {
		this.context = context;
		this.datas = datas;
	}

	public void setDatas(ArrayList datas) {
		this.datas = datas;
	}

	public int getCount() {
		return datas.size();
	}

	public Object getItem(int location) {
		return datas.get(location);
	}

	public long getItemId(int location) {
		return location;
	}

	public View getView(int location, View view, ViewGroup parent) {
		if(datas == null) {
			return null;
		}
		if(view == null) {
			DemoListItemView itemView = new DemoListItemView(context);
			itemView.updateView(datas.get(location));
			view = itemView;
		} else {
			((DemoListItemView) view).updateView(datas.get(location));
		}
		return view;
	}

}

adapter中最重要的是getView:
通过重写BaseAdapter中的方法,在实例化这个adapter时传入要显示的数据,然后用getView来显示每一个ListView的item,通过实例化刚才建立的View:DemoListItemView的方法updateView传入要显示在当前位置的数据项,然后返回处理完毕的view。

然后是activity的layout:
layout中只有一个ListView,我们通过在activity中载入数据,然后把数据传给刚才的 DemoListAdapter 的对象,再通过这个ListView的setAdapter方法把数据显示出来。



	
	

activity:

package com.zhang.test;

import java.util.ArrayList;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.widget.ListView;

import com.zhang.test.view.DemoListItemView;
import com.zhang.test.view.adapter.DemoListAdapter;

public class demoActivity extends Activity {

	private static final String TAG = "demoActivity";
	private Context context;
	private ListView listView;
	private ArrayList datas;
	private DemoListAdapter datasAdapter;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        context = this;
        listView = (ListView) findViewById(R.id.listView);
        datas = new ArrayList();
        loadData();
        datasAdapter = new DemoListAdapter(context, datas);
        listView.setAdapter(datasAdapter);
    }

    private void loadData() {
    	DemoListItemView.Data d;
    	for(int i=0; i<10; i++) {
    		d = new DemoListItemView.Data();
    		d.topText = "测试top";
    		d.bottomText = "测试bottom";
    		datas.add(d);
    	}
    }
}

activity中定义的几个变量:
listView:layout文件中的ListView
datas:自定义item的view要显示的数据
datasAdapter:DemoListAdapter实例化的对象,赋值后显示在ListView中

整个程序结构:

最终运行结果:

源码下载:
DemoListView.zip

今天在写程序时遇到一个问题:
通过Bitmap画一张图片,屏幕没有转换时没有问题,当转换3-4次横竖屏后,在createBitmap时报异常:bitmap size exceeds VM budget
google了下都是说一些什么只分配了8m内存啊,及时删掉不用的变量之类的,对我的程序帮助不大…

既然是只有转换横竖屏才会报错,加了个onConfigurationChanged不让activity每次都去调onCreate,oom就不见了.
不过还是没有解决oom的本质问题- -

透明的activity:
AndroidManifest.xml中找到要弹出的activity,加入theme:
android:theme=”@style/translucent”
res/values文件夹下建立styles.xml:






再新建colors.xml:
前2位:透明度00完全透明,99不透明
后6位:颜色

*有时候需要重启一下emulator,才会显示出透明颜色



#60000000

效果:
translucent

代码:
translucent

Toast:
效果:
toast

代码:
testToast

自定义view:
新建一个包com.view:

package com.view;

import com.test.R;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.EditText;
import android.widget.RelativeLayout;
import android.widget.TextView;

public class InputMode extends RelativeLayout {

	public static String TAG = "InputMode";
	public TextView label;
	public EditText text;

	public InputMode(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		// TODO Auto-generated constructor stub
	}

	public InputMode(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
	}

	public InputMode(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
	}

	public void initView() {
		Log.d(TAG, "initView()");
		this.label = (TextView) findViewById(R.id.input_mode_label);
		this.text = (EditText) findViewById(R.id.input_mode_text);
		this.text.getText();
	}

	/**
	 * 设置label文本
	 * @param str
	 */
	public void setLabelText(String str) {
		this.label.setText(str);
	}

	/**
	 * 设置输入框内容
	 * @param str
	 */
	public void setInputText(String str) {
		this.text.setText(str);
	}

	/**
	 * 设置输入框显示为密码
	 * @param flag
	 */
	public void setInputTextMode(boolean flag) {
		if(flag) {
			this.text.setTransformationMethod(android.text.method.PasswordTransformationMethod.getInstance());
		} else {
			this.text.setTransformationMethod(null);
		}
	}

	/**
	 * 获得输入框内容
	 * @return
	 */
	public String getInputText() {
		return this.text.getText().toString();
	}

	/**
	 * 设置label宽度
	 * @param width
	 */
	public void setLabelWidth(Integer width) {
		this.label.setWidth(width);
	}
}

之后新建一个layout:




	
	

调用:
在要加入自定义view的layout中:

	

activity中:

        InputMode username_im;
        username_im = (InputMode) findViewById(R.id.username_input);
        username_im.initView();
        username_im.setLabelText("Username:");
        username_im.setInputText("");

效果:
custom_view

代码:
customView

找了很久的东西,今天终于搞定了

     //隐藏软键盘
     ((InputMethodManager)getSystemService(INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(WidgetSearchActivity.this.getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);

     //显示软键盘,控件ID可以是EditText,TextView,android 1.6的SDK本身有问题,无法设置manifest文件或者直接show出软键盘,preformclick也不行,必须手动click一个控件
     ((InputMethodManager)getSystemService(INPUT_METHOD_SERVICE)).showSoftInput(控件ID, 0);