可拖动EditText的实现
昨天,群里面一个小伙伴发了个求助,要求实现一个可以拖动的EditText,本来以为这个应该不难,自定义继承EditText然后监听下OnTouch事件应该就可以了,后来想了想还有一些细节问题容易忽略,比如区分点击和滑动,软键盘呼出以后又回到原来地方的缘由,这个还是有一些细节需要深究的,废话不多说,上代码。
首先自定义DrawEdxtView,继承至EditText:
package com.yong.drawedit;
import android.app.Activity;
import android.content.Context;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
public class DrawEdxtView extends EditText implements OnTouchListener {
private Context mContext;
private int screenWidth, screenHeight;
private void getDisplayMetrics() {
DisplayMetrics dm = getResources().getDisplayMetrics();
screenWidth = dm.widthPixels;
screenHeight = dm.heightPixels - 50;
}
private int lastX, lastY;
private int downX, downY; // 按下View的X,Y坐标
private int upX, upY; // 放手View的X,Y坐标
private int rangeDifferenceX, rangeDifferenceY; // 放手和按下X,Y值差
private int mDistance = 10; // 设定点击事件的移动距离值
private int mL,mB,mR,mT;//重绘时layout的值
public DrawEdxtView(Context context) {
super(context);
mContext = context;
getDisplayMetrics();
setOnTouchListener(this);
}
public DrawEdxtView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
getDisplayMetrics();
setOnTouchListener(this);
}
public DrawEdxtView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mContext = context;
getDisplayMetrics();
setOnTouchListener(this);
}
/*隐藏键盘*/
public static void hideSoftInput(Activity mContext, View view) {
InputMethodManager imm = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm.isActive()) {
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
}
/*弹出键盘*/
public static void showSoftInput(Activity mContext, View view) {
InputMethodManager imm = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm.isActive()) {
imm.showSoftInput(view, 0);
}
}
public interface IOnKeyboardStateChangedListener{
public void openKeyboard();
}
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
downX = (int) event.getRawX();
downY = (int) event.getRawY();
lastX = (int) event.getRawX();// 获取触摸事件触摸位置的原始X坐标
lastY = (int) event.getRawY();
Log.d("按下:", downX + "----X轴坐标");
Log.d("按下:", downY + "----Y轴坐标");
break;
case MotionEvent.ACTION_MOVE:
int dx = (int) event.getRawX() - lastX;
int dy = (int) event.getRawY() - lastY;
mL = v.getLeft() + dx;
mB = v.getBottom() + dy;
mR = v.getRight() + dx;
mT = v.getTop() + dy;
if (mL < 0) {
mL = 0;
mR = mL + v.getWidth();
}
if (mT < 0) {
mT = 0;
mB = mT + v.getHeight();
}
if (mR > screenWidth) {
mR = screenWidth;
mL = mR - v.getWidth();
}
if (mB > screenHeight) {
mB = screenHeight;
mT = mB - v.getHeight();
}
v.layout(mL, mT, mR, mB);
Log.d("绘制:", "l="+mL+ ";t="+ mT+";r="+mR+";b="+mB);
lastX = (int) event.getRawX();
lastY = (int) event.getRawY();
v.postInvalidate();
v.setFocusable(false);
v.setFocusableInTouchMode(false);
hideSoftInput((Activity)mContext, v);
break;
case MotionEvent.ACTION_UP:
upX = (int) event.getRawX();
upY = (int) event.getRawY();
Log.d("离开:", upX + "----X轴坐标");
Log.d("离开:", upY + "----Y轴坐标");
rangeDifferenceX = upX - downX;
rangeDifferenceY = upY - downY;
if (rangeDifferenceX > 0 && rangeDifferenceX <= mDistance) {
if (rangeDifferenceY >= 0 && rangeDifferenceY <= mDistance) {
v.setFocusable(true);
v.setFocusableInTouchMode(true);
Log.d("是否是点击事件:", true + "");
} else {
if (rangeDifferenceY <= 0 && rangeDifferenceY >= -mDistance) {
v.setFocusable(true);
v.setFocusableInTouchMode(true);
Log.d("是否是点击事件:", true + "");
} else {
v.setFocusable(false);
v.setFocusableInTouchMode(false);
Log.d("是否是点击事件:", false + "");
}
}
} else {
if (rangeDifferenceX <= 0 && rangeDifferenceX >= -mDistance) {
v.setFocusable(true);
v.setFocusableInTouchMode(true);
Log.d("是否是点击事件:", true + "");
} else {
v.setFocusable(false);
v.setFocusableInTouchMode(false);
Log.d("是否是点击事件:", false + "");
}
}
break;
default:
break;
}
return false;
}
}
在这个自定义控件里面主要干了一件事情,监听OnTouch事件,然后判断是拖动还是点击事件,如果是拖动,就让EditText无法获取焦点,保证拖动事件不会被焦点事件中断,在拖动的过程中,不断的postInvalidate(),更新界面。
其次,在用到的地方使用布局文件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/keyboardRelativeLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<com.yong.drawedit.DrawEdxtView
android:id="@+id/drawEdit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|center_vertical"
android:layout_marginLeft="50dip"
android:focusable="false"
android:focusableInTouchMode="false"
android:gravity="center_vertical|center_horizontal"
android:hint="拖动试试"
android:text="" />
</LinearLayout>
最后还有一个需要注意的地方:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.yong.drawedit"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.yong.drawedit.MainActivity"
android:label="@string/app_name"
android:windowSoftInputMode="adjustNothing">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
在Manifest中需要设置软键盘的模式,不然呼出软键盘以后会对布局有一定的影响。
代码奉上:DrawViewDemo.zip
你好,我用的android 5.0版本也遇到楼上的问题,请问有解决的办法吗
你这个还是有bug,输入etittext里面的内容的时候,就会自动给顶到原位置去
是所有机型还是个别机型?我当时用的原生系统没有问题,可能没有关注到兼容性问题。