一般,用户经常会通过界面与应用交互,Android框架采用事件驱动的形式与用户交互,那如何处理用户界面中触发的事件?
可以通过从用户交互的View设置事件监听器的方式来实现对事件的处理,一个事件监听器是View类中一个包含单一回调方法的接口。当注册了监听器的View发生了对应的监听事件时,Android框架就会回调相应的监听方法。
常见的用户事件
- 点击事件
- 选择事件
- 触屏事件
- 长按事件
- 按键事件
点击事件
点击事件是事件机制中最常见的事件,通过对控件绑定View.OnClickListener 实现单击事件的监听
点击事件的四种写法
布局中设置onclick控件属性
假设有个Layout布局文件,里面有个Button控件,button在xml里配置的属性如下,click可以随意命名,但最好有实际意义
<Button
android:id="@+id/bt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="click"/>
在activity里写公有函数
public void click(View view){
//TODO 必须公有,函数名必须与控件的onclick属性值一致
}
2.内部类实现
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button bt=(Button) findViewById(R.id.bt);
bt.setOnClickListener(new MyButtonClick());
}
class MyButtonClick implements View.OnClickListener{
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
}
3.匿名内部类实现
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button bt=(Button) findViewById(R.id.bt);
bt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
});
}
4.Activity实现监听接口
public class MainActivity extends Activity implements View.OnClickListener{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button bt=(Button) findViewById(R.id.bt);
bt.setOnClickListener(this);
}
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
}
其中,匿名内部类不适合在有多个控件需要点击事件的条件。其他的都可以通过对view对象id的判断来处理多个控件的点击
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bt:
//TODO
break;
case R.id.another:
//TODO
break;
default:
break;
}
}
但即使如此,我们还要给对应的控件添加监听,如果你是采用代码的方式添加视图,可以在添加的时候顺便加监听,但如果你是采用XML的方式加控件,那么多控件难道要一个一个写setOnClick,我们可以找出页面所有控件,循环加监听
public class MainActivity extends Activity implements View.OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
View view = getWindow().getDecorView();
List<View> views=getAllChildViews(view);
System.out.println(views.size());
for (View v : views) {
view.setOnClickListener(this);
}
}
/**
* 采用递归方式取出所有子控件,注意这里还包含了ActionBar的所有子控件
* @param view
* @return List<View>
*/
private List<View> getAllChildViews(View view) {
List<View> allchildren = new ArrayList<View>();
if (view instanceof ViewGroup) {
ViewGroup viewgroup = (ViewGroup) view;
for (int i = 0; i < viewgroup.getChildCount(); i++) {
View viewchild = viewgroup.getChildAt(i);
if(viewchild instanceof ViewGroup){
allchildren.addAll(getAllChildViews(viewchild));
}
else{
allchildren.add(viewchild);
}
}
}
return allchildren;
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bt1:
// TODO
break;
case R.id.bt2:
// TODO
break;
case R.id.bt3:
// TODO
break;
case R.id.bt4:
// TODO
break;
case R.id.bt5:
// TODO
break;
case R.id.bt6:
// TODO
break;
default:
break;
}
}
}
选择事件
复选事件
复选事件的监听接口:CompoundButton.OnCheckedChangeListener
复选控件CheckBox 有两种状态:选中与未选中状态
Demo:明密文切换
//密码输入框
final EditText infoEdt=(EditText)findViewById(R.id.info_edt);
//CheckBox
CheckBox checkBox=(CheckBox)findViewById(R.id.checkbox);
checkBox.setOnCheckedChangeListener(new
CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
if(isChecked){
把EditText隐藏的文本内容还原
infoEdt.setTransformationMethod(new
HideReturnsTransformationMethod());
}else{
//把EditText的内容用密码的方式隐藏起来
infoEdt.setTransformationMethod(new
PasswordTransformationMethod());
}
}
});
一般我们用复选事件是加给许多checkBox的,最好把这些checkBox放在一个ViewGroup里,方便取出所有checkbox的值。
<LinearLayout
android:id="@+id/ll"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckBox
android:id="@+id/rb1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="广州"
android:checked="true"/>
<CheckBox
android:id="@+id/rb2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="北京"/>
<CheckBox
android:id="@+id/rb3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="上海"/>
</LinearLayout>
<Button
android:id="@+id/bt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="确认"/>
public class MainActivity extends Activity implements View.OnClickListener {
//存放checkbox状态
boolean[] checkstates;
//checkbox的父控件
private LinearLayout ll;
private Button bt;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ll=(LinearLayout) findViewById(R.id.ll);
findViewById(R.id.bt).setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bt:
StringBuffer s=new StringBuffer();
checkstates=new boolean[ll.getChildCount()];
//循环遍历取出所有checkbox的状态
for(int i=0;i<ll.getChildCount();i++){
CheckBox checkBox=(CheckBox) ll.getChildAt(i);
checkstates[i]=checkBox.isChecked();
s.append(checkBox.isChecked()+",");
}
Toast.makeText(getBaseContext(), s.toString(), Toast.LENGTH_SHORT).show();
break;
default:
break;
}
}
}
单选事件
单选事件的监听接口:RadioGroup.OnCheckedChangeListener
RadioButton与RadioGroup组合使用才能实现单选功能
Demo
<RadioGroup
android:id="@+id/rg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<RadioButton
android:id="@+id/rb1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="广州"
<!-- 默认被选择 -->
android:checked="true"/>
<RadioButton
android:id="@+id/rb2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="北京"/>
<RadioButton
android:id="@+id/rb3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="上海"/>
</RadioGroup>
RadioGroup radioGroup=(RadioGroup) findViewById(R.id.rg);
radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
/** 选择状态改变监听
* RadioGroup:单选组
* checkedId:被改变的控件的资源id
*/
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
//用吐司显示被选radiobutton的文本
RadioButton radioButton=(RadioButton)findViewById(checkedId);
Toast.makeText(getBaseContext(), radioButton.getText(), Toast.LENGTH_SHORT).show();
}
});
长按与触屏事件
长按事件监听接口:View.OnLongClickListener
触屏事件监听接口:View.OnTouchListener
<TextView
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="点我"
android:gravity="center"/>
TextView tv=(TextView) findViewById(R.id.tv);
tv.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
Log.i("onLongClick", "onlongclick");
return false;
}
});
tv.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.i("onTouch", event.toString());
return false;
}
});
}
TextView tv=(TextView) findViewById(R.id.tv);
tv.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
Log.i("onLongClick", "onlongclick");
return false;
}
});
tv.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.i("onTouch", event.toString().substring(0, event.toString().indexOf(",")));
return false;
}
});
它的触发顺序是这样的
如果你在onTouch里返回true,则无法触发onlongclick,因为true表示事件被消费了,具体还得研究源码才知道为什么。
输入框EditText输入监听事件
EditText et=(EditText) findViewById(R.id.et);
et.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// TODO Auto-generated method stub
Log.i("onTextChanged", "s="+s+",start="+start+",before="+before+",count="+count);
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
Log.i("beforeTextChanged", "s="+s+",start="+start+",count="+count+",after="+after);
}
@Override
public void afterTextChanged(Editable s) {
Log.i("afterTextChanged", "s="+s);
}
});
输入框输入 1 2 3
我们可以通过输入框监听事件来控制输入的字数,现在愈多即时搜索也是用该监听来写的