motioneventandroid
‘壹’ 在Android编程中,MotionEvent中的ACTION_MOVE如何获取每一个触摸到的点的坐标
Android编程中Touch事件中的MotionEvent已经记录了触摸的x y坐标了。
intx = event.getX(); 得到触摸的x轴坐标。
inty = event.getY();得到触摸的y轴坐标。
示例代码:
switch(event.getAction()){
case MotionEvent.ACTION_MOVE:
intx = event.getX();
inty = event.getY();
break;
}
‘贰’ android后台服务怎么获取motionevent事件
publi boolean dispatchTouchEvent(MotionEvent event)
public boolean onTouchEvent(MotionEvent event)
ViewGroup.java中
public boolean dispatchTouchEvent(MotionEvent event)
public boolean onTouchEvent(MotionEvent event)
public boolean onInterceptTouchEvent(MotionEvent event)
在组件嵌套的情况下,对于事件的响应处理会从最顶层的组件不断向子组件传递,一直到最后的View组件。
可以看到ViewGroup中比View中多出了一个onInterceptTouchEvent方法,这是因为ViewGroup组件可以存在子组件,因此需要通过Intercept判断是否
将该事件传递到子组件中。
‘叁’ 懒人划划在android上是怎么实现的任意界面从屏幕边缘滑出的
android弹出一个占屏幕一半的菜单,可以使用popupwindow,设置弹出的xy轴的距离占据屏幕一半即可,如下代码:packagecom.example.hellopopupwindow;importandroid.os.Bundle;importandroid.app.Activity;importandroid.content.Context;importandroid.util.Log;importandroid.view.LayoutInflater;importandroid.view.MotionEvent;importandroid.view.View;importandroid.view.View.OnClickListener;importandroid.view.View.OnTouchListener;importandroid.view.ViewGroup.LayoutParams;importandroid.widget.Button;importandroid.widget.PopupWindow;importandroid.widget.Toast;{privateContextmContext=null;@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mContext=this;Buttonbutton=(Button)findViewById(R.id.button);button.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(Viewview){showPopupWindow(view);}});}privatevoidshowPopupWindow(Viewview){//一个自定义的布局,作为显示的内容ViewcontentView=LayoutInflater.from(mContext).inflate(R.layout.pop_window,null);//设置按钮的点击事件Buttonbutton=(Button)contentView.findViewById(R.id.button1);button.setOnClickListener(newOnClickListener(){@OverridepublicvoidonClick(Viewv){Toast.makeText(mContext,"buttonispressed",Toast.LENGTH_SHORT).show();}});finalPopupWindowpopupWindow=newPopupWindow(contentView,LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT,true);popupWindow.setTouchable(true);popupWindow.setTouchInterceptor(newOnTouchListener(){@OverridepublicbooleanonTouch(Viewv,MotionEventevent){Log.i("mengdd","onTouch:");returnfalse;//这里如果返回true的话,touch事件将被拦截//拦截后PopupWindow的onTouchEvent不被调用,这样点击外部区域无法dismiss}});//如果不设置PopupWindow的背景,无论是点击外部区域还是Back键都无法dismiss弹框//我觉得这里是API的一个bugpopupWindow.setBackgroundDrawable(getResources().getDrawable(R.drawable.selectmenu_bg_downward));//设置好参数之后再showpopupWindow.showAsDropDown(view);}}
‘肆’ Android上这种布局和联动的滑动效果是怎么做到的
实现思路简介:viewpager是全屏的,所有页面共用的header,根据当前页面listview或者scrollview的滑动距离设置translationY;切换tab时,根据当前header的高度调整下一个tab页面的滚动距离。缺点:封面上有很多响应时,需要自己进行手势处理
给点提示:
MainActivity文件中代码:
package com.android.flip;
import android.app.Activity;
import android.os.Bundle;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.GestureDetector.OnGestureListener;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.ViewFlipper;
/**
* Android实现左右滑动效果
* @Description: Android实现左右滑动效果
* @File: MainActivity.java
* @Package com.android.flip
* @Author Hanyonglu
* @Date 2012-02-12 上午10:44:04
* @Version V1.0
*/
public class MainActivity extends Activity implements OnGestureListener {
private ViewFlipper flipper;
private GestureDetector detector;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
detector = new GestureDetector(this);
flipper = (ViewFlipper) this.findViewById(R.id.ViewFlipper1);
flipper.addView(addImageView(R.drawable.one));
flipper.addView(addImageView(R.drawable.two));
flipper.addView(addImageView(R.drawable.three));
flipper.addView(addImageView(R.drawable.four));
flipper.addView(addImageView(R.drawable.five));
}
private View addImageView(int id) {
ImageView iv = new ImageView(this);
iv.setImageResource(id);
return iv;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
return this.detector.onTouchEvent(event);
}
@Override
public boolean onDown(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
if (e1.getX() - e2.getX() > 120) {
this.flipper.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.push_left_in));
this.flipper.setOutAnimation(AnimationUtils.loadAnimation(this, R.anim.push_left_out));
this.flipper.showNext();
return true;
} else if (e1.getX() - e2.getX() < -120) {
this.flipper.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.push_right_in));
this.flipper.setOutAnimation(AnimationUtils.loadAnimation(this, R.anim.push_right_out));
this.flipper.showPrevious();
return true;
}
return false;
}
@Override
public void onLongPress(MotionEvent e) {
// TODO Auto-generated method stub
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY) {
// TODO Auto-generated method stub
return false;
}
@Override
public void onShowPress(MotionEvent e) {
// TODO Auto-generated method stub
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}
}
‘伍’ android 怎么实现左侧导航栏
Android左侧推出导航菜单可以让Activity继承PopupWindow类来实现的弹出窗体,布局可以根据自己定义设计。弹出效果主要使用了translate和alpha样式实现。具体的做法是下列代码:
第一步:设计弹出窗口xml:
Xml代码
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="vertical"
>
<LinearLayout
android:id="@+id/pop_layout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="vertical"
android:layout_alignParentBottom="true"
android:background="@drawable/btn_style_alert_dialog_background"
>
<Button
android:id="@+id/btn_take_photo"
android:layout_marginLeft="20dip"
android:layout_marginRight="20dip"
android:layout_marginTop="20dip"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="拍照"
android:background="@drawable/btn_style_alert_dialog_button"
android:textStyle="bold"
/>
<Button
android:id="@+id/btn_pick_photo"
android:layout_marginLeft="20dip"
android:layout_marginRight="20dip"
android:layout_marginTop="5dip"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="从相册选择"
android:background="@drawable/btn_style_alert_dialog_button"
android:textStyle="bold"
/>
<Button
android:id="@+id/btn_cancel"
android:layout_marginLeft="20dip"
android:layout_marginRight="20dip"
android:layout_marginTop="15dip"
android:layout_marginBottom="15dip"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="取消"
android:background="@drawable/btn_style_alert_dialog_cancel"
android:textColor="#ffffff"
android:textStyle="bold"
/>
</LinearLayout>
</RelativeLayout>
第二步:创建SelectPicPopupWindow类继承PopupWindow:
Java代码
import android.app.Activity;
import android.content.Context;
import android.graphics.drawable.ColorDrawable;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.PopupWindow;
public class SelectPicPopupWindow extends PopupWindow {
private Button btn_take_photo, btn_pick_photo, btn_cancel;
private View mMenuView;
public SelectPicPopupWindow(Activity context,OnClickListener itemsOnClick) {
super(context);
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mMenuView = inflater.inflate(R.layout.alert_dialog, null);
btn_take_photo = (Button) mMenuView.findViewById(R.id.btn_take_photo);
btn_pick_photo = (Button) mMenuView.findViewById(R.id.btn_pick_photo);
btn_cancel = (Button) mMenuView.findViewById(R.id.btn_cancel);
//取消按钮
btn_cancel.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
//销毁弹出框
dismiss();
}
});
//设置按钮监听
btn_pick_photo.setOnClickListener(itemsOnClick);
btn_take_photo.setOnClickListener(itemsOnClick);
//设置SelectPicPopupWindow的View
this.setContentView(mMenuView);
//设置SelectPicPopupWindow弹出窗体的宽
this.setWidth(LayoutParams.FILL_PARENT);
//设置SelectPicPopupWindow弹出窗体的高
this.setHeight(LayoutParams.WRAP_CONTENT);
//设置SelectPicPopupWindow弹出窗体可点击
this.setFocusable(true);
//设置SelectPicPopupWindow弹出窗体动画效果
this.setAnimationStyle(R.style.AnimBottom);
//实例化一个ColorDrawable颜色为半透明
ColorDrawable dw = new ColorDrawable(0xb0000000);
//设置SelectPicPopupWindow弹出窗体的背景
this.setBackgroundDrawable(dw);
//mMenuView添加OnTouchListener监听判断获取触屏位置如果在选择框外面则销毁弹出框
mMenuView.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
int height = mMenuView.findViewById(R.id.pop_layout).getTop();
int y=(int) event.getY();
if(event.getAction()==MotionEvent.ACTION_UP){
if(y<height){
dismiss();
}
}
return true;
}
});
}
}
第三步:编写MainActivity类实现测试:
Java代码
import android.app.Activity;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TextView;
public class MainActivity extends Activity {
//自定义的弹出框类
SelectPicPopupWindow menuWindow;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv = (TextView) this.findViewById(R.id.text);
//把文字控件添加监听,点击弹出自定义窗口
tv.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
//实例化SelectPicPopupWindow
menuWindow = new SelectPicPopupWindow(MainActivity.this, itemsOnClick);
//显示窗口
menuWindow.showAtLocation(MainActivity.this.findViewById(R.id.main), Gravity.BOTTOM|Gravity.CENTER_HORIZONTAL, 0, 0); //设置layout在PopupWindow中显示的位置
}
});
}
//为弹出窗口实现监听类
private OnClickListener itemsOnClick = new OnClickListener(){
public void onClick(View v) {
menuWindow.dismiss();
switch (v.getId()) {
case R.id.btn_take_photo:
break;
case R.id.btn_pick_photo:
break;
default:
break;
}
}
};
}
上述的代码实现了从底部弹出,也可以根据PopupWindow类设置从左下部弹出。
Android的对话框有两种:PopupWindow和AlertDialog。它们的不同点在于:
AlertDialog的位置固定,而PopupWindow的位置可以随意
AlertDialog是非阻塞线程的,而PopupWindow是阻塞线程的
PopupWindow的位置按照有无偏移分,可以分为偏移和无偏移两种;按照参照物的不同,可以分为相对于某个控件(Anchor锚)和相对于父控件。具体如下
showAsDropDown(View anchor):相对某个控件的位置(正左下方),无偏移
showAsDropDown(View anchor, int xoff, int yoff):相对某个控件的位置,有偏移
showAtLocation(View parent, int gravity, int x, int y):相对于父控件的位置(例如正中央Gravity.CENTER,下方Gravity.BOTTOM等),可以设置偏移或无偏移
‘陆’ android如何实现通过上拉由一个activity切换到另一个activity
应用了Activity的ontouchEvent方法监听手指点击事件,手指滑动的时候会先按下,滑倒另一个地方再抬起,就可以根据按下的坐标和抬起的坐标算出用户是往哪一个方向滑动了。
package com.example.testtt;
import android.app.Activity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.widget.Toast;
public class MainActivity extends Activity {
//手指按下的点为(x1, y1)手指离开屏幕的点为(x2, y2)
float x1 = 0;
float x2 = 0;
float y1 = 0;
float y2 = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
//继承了Activity的onTouchEvent方法,直接监听点击事件
if(event.getAction() == MotionEvent.ACTION_DOWN) {
//当手指按下的时候
x1 = event.getX();
y1 = event.getY();
}
if(event.getAction() == MotionEvent.ACTION_UP) {
//当手指离开的时候
x2 = event.getX();
y2 = event.getY();
if(y1 - y2 > 50) {
Toast.makeText(MainActivity.this, "向上滑", Toast.LENGTH_SHORT).show();
} else if(y2 - y1 > 50) {
Toast.makeText(MainActivity.this, "向下滑", Toast.LENGTH_SHORT).show();
//这里就可以跳转了
Intent intent=new Intent(this,xxxx.class); //方法1
startActivity(intent);
} else if(x1 - x2 > 50) {
Toast.makeText(MainActivity.this, "向左滑", Toast.LENGTH_SHORT).show();
} else if(x2 - x1 > 50) {
Toast.makeText(MainActivity.this, "向右滑", Toast.LENGTH_SHORT).show();
}
}
return super.onTouchEvent(event);
}
}
‘柒’ Android的MotionEventCompat类中的findPointerIndex()方法有这么一句解释,是什么意思
ECLAIR是android的某个版本,是一个比较老的版本,没记错应该是2.0
MotionEventCompat是兼容包的一个类,对应的类是MotionEvent,这个类工作内容是触屏事件的抽象,比如 ACTION_DOWN/MOVE/UP,Pointer,getX() getY()等操作。
兼容包是为了让老版本的手机能运行对应于新版本SDK开发的程序,而开发出来的软件包。
该注释意思是说,如果你在ECLAIR(2.0)版本之前的设备上调用
findPointerIndex方法,那么只会返回-1,不会作任何操作。
findPointerIndex是查找Pointer的索引,pointer是手势中按下手指的抽象
一个手势中,可以有多个手指接触屏幕,按接触的先后顺序,被赋予不同的pointer id。
‘捌’ 请简述什么是android事件处理,并分析两种android事件处理机制的实现过程和区别
UI编程通常都会伴随事件处理,Android也不例外,它提供了两种方式的事件处理:基于回调的事件处理和基于监听器的事件处理。
对于基于监听器的事件处理而言,主要就是为Android界面组件绑定特定的事件监听器;对于基于回调的事件处理而言,主要做法是重写Android组件特定的回调函数,Android大部分界面组件都提供了事件响应的回调函数,我们主要重写它们就行。
一 基于监听器的事件处理
相比于基于回调的事件处理,这是更具“面向对象”性质的事件处理方式。在监听器模型中,主要涉及三类对象:
1)事件源Event Source:产生事件的来源,通常是各种组件,如按钮,窗口等。
2)事件Event:事件封装了界面组件上发生的特定事件的具体信息,如果监听器需要获取界面组件上所发生事件的相关信息,一般通过事件Event对象来传递。
3)事件监听器Event Listener:负责监听事件源发生的事件,并对不同的事件做相应的处理。
基于监听器的事件处理机制是一种委派式Delegation的事件处理方式,事件源将整个事件委托给事件监听器,由监听器对事件进行响应处理。这种处理方式将事件源和事件监听器分离,有利于提供程序的可维护性。
举例:
View类中的OnLongClickListener监听器定义如下:(不需要传递事件)
[java] view plainprint?
public interface OnLongClickListener {
boolean onLongClick(View v);
}
public interface OnLongClickListener {
boolean onLongClick(View v);
}
View类中的OnLongClickListener监听器定义如下:(需要传递事件MotionEvent)
[java] view plainprint?
public interface OnTouchListener {
boolean onTouch(View v, MotionEvent event);
}
public interface OnTouchListener {
boolean onTouch(View v, MotionEvent event);
}
二 基于回调的事件处理
相比基于监听器的事件处理模型,基于回调的事件处理模型要简单些,该模型中,事件源和事件监听器是合一的,也就是说没有独立的事件监听器存在。当用户在GUI组件上触发某事件时,由该组件自身特定的函数负责处理该事件。通常通过重写Override组件类的事件处理函数实现事件的处理。
举例:
View类实现了KeyEvent.Callback接口中的一系列回调函数,因此,基于回调的事件处理机制通过自定义View来实现,自定义View时重写这些事件处理方法即可。
[java] view plainprint?
public interface Callback {
// 几乎所有基于回调的事件处理函数都会返回一个boolean类型值,该返回值用于
// 标识该处理函数是否能完全处理该事件
// 返回true,表明该函数已完全处理该事件,该事件不会传播出去
// 返回false,表明该函数未完全处理该事件,该事件会传播出去
boolean onKeyDown(int keyCode, KeyEvent event);
boolean onKeyLongPress(int keyCode, KeyEvent event);
boolean onKeyUp(int keyCode, KeyEvent event);
boolean onKeyMultiple(int keyCode, int count, KeyEvent event);
}
public interface Callback {
// 几乎所有基于回调的事件处理函数都会返回一个boolean类型值,该返回值用于
// 标识该处理函数是否能完全处理该事件
// 返回true,表明该函数已完全处理该事件,该事件不会传播出去
// 返回false,表明该函数未完全处理该事件,该事件会传播出去
boolean onKeyDown(int keyCode, KeyEvent event);
boolean onKeyLongPress(int keyCode, KeyEvent event);
boolean onKeyUp(int keyCode, KeyEvent event);
boolean onKeyMultiple(int keyCode, int count, KeyEvent event);
}
三 比对
基于监听器的事件模型符合单一职责原则,事件源和事件监听器分开实现;
Android的事件处理机制保证基于监听器的事件处理会优先于基于回调的事件处理被触发;
某些特定情况下,基于回调的事件处理机制会更好的提高程序的内聚性。
四 基于自定义监听器的事件处理流程
在实际项目开发中,我们经常需要自定义监听器来实现自定义业务流程的处理,而且一般都不是基于GUI界面作为事件源的。这里以常见的app自动更新为例进行说明,在自动更新过程中,会存在两个状态:下载中和下载完成,而我们的程序需要在这两个状态做不同的事情,“下载中”需要在UI界面上实时显示软件包下载的进度,“下载完成”后,取消进度条的显示。这里进行一个模拟,重点在说明自定义监听器的事件处理流程。
4.1)定义事件监听器如下:
‘玖’ android怎样传递一个控件
public boolean dispatchTouchEvent(MotionEvent ev){}
用于事件的分发,Android中所有的事件都必须经过这个方法的分发,然后决定是自身消费当前事件还是继续往下分发给子控件处理。返回true表示不继续分发,事件没有被消费。
public boolean onInterceptTouchEvent(MotionEvent arg0){}
用于事件的处理,返回true表示消费处理当前事件,返回false则不处理,交给子控件进行继续分发。
public boolean onTouchEvent(MotionEvent arg0){}
负责事件的拦截,返回true的时候表示拦截当前事件,不继续往下分发,交给自身的onTouchEvent进行处理。返回false则不拦截,继续往下传。
举例说明三个方法之间的传递关系,加入界面如下图:
例:Android
Viewpage禁止滑动屏幕(如果是其他view可以自定义控件,然后重写这几个方法)
Android事件机制是从父View传向子View的,可以去检测你当前子View是不是在有可滑动控件等,决定事件是否拦截,但是这个麻烦,而且并不能解决所有的问题(必须检测触摸点是否在这个控件上面),其实有比较简单的方法,在你嵌套的控件中注入ViewPager实例,然后在onTouchEvent,onInterceptTouchEvent,dispatchTouchEvent里面告诉父View,也就是ViewPager不要拦截该控件上的触摸事件。
详细
‘拾’ android为何MotionEvent.ACTION_DOWN失效
首先检查这个view的 父view 是不是重写了onInterceptTouchEvent方法并且返回了true.如果是,则该父View里面所有的子view是不能获得事件的。
然后检查该view的子view是不是重写了onTouch方法并且返回了true,或者添加了onclicklistener,并且该子view填充了整个父view,如果是,则子view会消费当前事件,不能返回到当前view。