在开发中其实不论前台、后台都会留一些后门,方便管理人员操作(有点超级权限的意思),但是这样的入口我们又不能让用户直接看到,所以就有一些芝麻开门的操作 ~
今天真是个好日子啊 - 2020.5.20, 计划终究还是赶不上变化 ~
Android系统自带的一种长按监听,长按时间差不多在0.5秒-1.5秒左右,如果入口想做的深一点,其实不必考虑这种,因为有的用户可能无意就会触发到 ~ 同时不太利于扩展,例如领导说做个5秒响应,那就凉凉了~
当然 - 如果说要求没有那么严格,那么可以直接使用这种方式,毕竟系统自带,分秒实现 ~
findViewById(R.id.btn_1).setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
Toast.makeText(MainActivity.this, "触发:隐藏入口", Toast.LENGTH_LONG).show();
return true;
}
});
此种方式主要利用了Android中onTouch机制,在手指Down的时候记录当前时间,UP的时候计算时间差 ~
但是有一些瑕疵,因为你要一直不抬起手指的话,岂不是一直进不去隐藏入口 …
Long startTime;
Long endTime;
findViewById(R.id.btn_2).setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//记录起始时间
startTime = System.currentTimeMillis();
break;
case MotionEvent.ACTION_UP:
//获取手指抬起时间,然后计算按压操作的时间差
endTime = System.currentTimeMillis();
if (endTime - startTime > 3 * 1000) {
Log.e("tag", "触发:隐藏入口");
Toast.makeText(MainActivity.this, "触发:隐藏入口", Toast.LENGTH_LONG).show();
} else {
Log.e("tag", "未超过5秒");
Toast.makeText(MainActivity.this, "未超过5秒", Toast.LENGTH_LONG).show();
}
break;
default:
break;
}
return true;
}
});
起初我想着通过onTouch的Down事件记录时间和按压状态,开启计时器,当满足条件则开启入口,同时UP的时候判断是时间差,取消计时器,看是否满足开启入口条件,但是果断使用TimerTask 后如果第二次去创建调用schedule会报错 ~ 一时间想不到什么好的方式去处理,就直接搜索到了成型的方法 … 当然也是通过OnTouch这种方式执行的 ~ 但是有Handler的使用哈 ~
以下方法,早已流传多时,使用也确实没什么问题
LongClickUtils(此类可直接copy)
package nk.com.hideentrance;
import android.os.Handler;
import android.view.MotionEvent;
import android.view.View;
/**
* @author MrLiu
* @date 2020/5/20
* desc
*/
public class LongClickUtils {
private static final String TAG = "LongClickUtils";
/**
* @param handler 外界handler(为了减少handler的泛滥使用,最好全局传handler引用,如果没有就直接传 new Handler())
* @param longClickView 被长按的视图(任意控件)
* @param delayMillis 长按时间,毫秒
* @param longClickListener 长按回调的返回事件
*/
public static void setLongClick(final Handler handler, final View longClickView, final long delayMillis, final View.OnLongClickListener longClickListener) {
longClickView.setOnTouchListener(new View.OnTouchListener() {
private int TOUCH_MAX = 50;
private int mLastMotionX;
private int mLastMotionY;
@Override
public boolean onTouch(View v, MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// 每次按下重新计时
// 按下前,先移除 已有的Runnable回调,防止用户多次单击导致多次回调长按事件的bug
handler.removeCallbacks(r);
mLastMotionX = x;
mLastMotionY = y;
// 按下时,开始计时
handler.postDelayed(r, delayMillis);
break;
case MotionEvent.ACTION_MOVE:
if (Math.abs(mLastMotionX - x) > TOUCH_MAX || Math.abs(mLastMotionY - y) > TOUCH_MAX) {
// 移动误差阈值
// xy方向判断
// 移动超过阈值,则表示移动了,就不是长按(看需求),移除 已有的Runnable回调
handler.removeCallbacks(r);
}
break;
case MotionEvent.ACTION_UP:
// 抬起时,移除已有Runnable回调,抬起就算长按了(不需要考虑用户是否长按了超过预设的时间)
handler.removeCallbacks(r);
break;
}
//onclick等其他事件不能用请改这里
return true;
}
private Runnable r = new Runnable() {
@Override
public void run() {
// 回调给用户,用户可能传null,需要判断null
if (longClickListener != null) {
longClickListener.onLongClick(longClickView);
}
}
};
});
}
}
LongClickUtils.setLongClick(new Handler(), view, 3000, new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
Toast.makeText(MainActivity.this, "触发:隐藏入口", Toast.LENGTH_LONG).show();
return true;
}
});
这份功能代码其实网上早就有了,主要是在一个时间差内记录用户的点击次数是否达标,如果满足条件即出发入口,反之重置时间与次数 ~
//临时时间
private long mTempTime;
//点击次数
private int mClickNum;
/*规定时间内:点击次数的方式*/
findViewById(R.id.btn_3).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
long time = System.currentTimeMillis();
//第一次点击隐藏入口,保存临时时间
if (mTempTime == 0) {
mTempTime = time;
} else {
//这里设置两秒的超时时间,如果超过两秒,重置状态
if (time - mTempTime > 2000) {
//给临时时间和点击次数进行初始化
mTempTime = time;
mClickNum = 0;
return;
}
mClickNum++;
mTempTime = time;
//因为一次点击走if语句,这里可以设置对应的点击次数,但是最少也要2次,不然用这个没有意义,mClickNum == 连续点击数-1
if (mClickNum == 4) {
Toast.makeText(MainActivity.this, "连续点击五次", Toast.LENGTH_SHORT).show();
//给临时时间和点击次数进行初始化
mTempTime = 0;
mClickNum = 0;
}
}
}
});
可通过此处,下载Demo ~
LongClickUtils(针对时长监听,此类可直接copy)
package nk.com.hideentrance;
import android.os.Handler;
import android.view.MotionEvent;
import android.view.View;
/**
* @author MrLiu
* @date 2020/5/20
* desc
*/
public class LongClickUtils {
private static final String TAG = "LongClickUtils";
/**
* @param handler 外界handler(为了减少handler的泛滥使用,最好全局传handler引用,如果没有就直接传 new Handler())
* @param longClickView 被长按的视图(任意控件)
* @param delayMillis 长按时间,毫秒
* @param longClickListener 长按回调的返回事件
*/
public static void setLongClick(final Handler handler, final View longClickView, final long delayMillis, final View.OnLongClickListener longClickListener) {
longClickView.setOnTouchListener(new View.OnTouchListener() {
private int TOUCH_MAX = 50;
private int mLastMotionX;
private int mLastMotionY;
@Override
public boolean onTouch(View v, MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// 每次按下重新计时
// 按下前,先移除 已有的Runnable回调,防止用户多次单击导致多次回调长按事件的bug
handler.removeCallbacks(r);
mLastMotionX = x;
mLastMotionY = y;
// 按下时,开始计时
handler.postDelayed(r, delayMillis);
break;
case MotionEvent.ACTION_MOVE:
if (Math.abs(mLastMotionX - x) > TOUCH_MAX || Math.abs(mLastMotionY - y) > TOUCH_MAX) {
// 移动误差阈值
// xy方向判断
// 移动超过阈值,则表示移动了,就不是长按(看需求),移除 已有的Runnable回调
handler.removeCallbacks(r);
}
break;
case MotionEvent.ACTION_UP:
// 抬起时,移除已有Runnable回调,抬起就算长按了(不需要考虑用户是否长按了超过预设的时间)
handler.removeCallbacks(r);
break;
}
//onclick等其他事件不能用请改这里
return true;
}
private Runnable r = new Runnable() {
@Override
public void run() {
// 回调给用户,用户可能传null,需要判断null
if (longClickListener != null) {
longClickListener.onLongClick(longClickView);
}
}
};
});
}
}
package nk.com.hideentrance;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
//Down按下时间
Long startTime;
//UP抬起时间
Long endTime;
//临时时间
private long mTempTime;
//点击次数
private int mClickNum;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/**
*长按监听 (原生版)
*/
findViewById(R.id.btn_1).setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
Toast.makeText(MainActivity.this, "触发:隐藏入口", Toast.LENGTH_LONG).show();
return true;
}
});
/**
*长按时长监听(乞丐版)
*/
findViewById(R.id.btn_2).setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startTime = System.currentTimeMillis();
Log.e("tag", "startTime:" + startTime);
break;
case MotionEvent.ACTION_UP:
endTime = System.currentTimeMillis();
Log.e("tag", "开始:" + startTime);
Log.e("tag", "结束:" + endTime);
if (endTime - startTime > 3 * 1000) {
Log.e("tag", "触发:隐藏入口");
Toast.makeText(MainActivity.this, "触发:隐藏入口", Toast.LENGTH_LONG).show();
} else {
Log.e("tag", "未超过5秒");
Toast.makeText(MainActivity.this, "未超过5秒", Toast.LENGTH_LONG).show();
}
break;
default:
break;
}
return true;
}
});
/**
*长按时长监听(主推:土豪版)
*/
LongClickUtils.setLongClick(new Handler(), findViewById(R.id.btn_3), 3000, new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
Toast.makeText(MainActivity.this, "触发:隐藏入口", Toast.LENGTH_LONG).show();
return true;
}
});
/**
*规定时间,点击次数(主推:土豪版)
*/
findViewById(R.id.btn_4).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
long time = System.currentTimeMillis();
//第一次点击隐藏入口,保存临时时间
if (mTempTime == 0) {
mTempTime = time;
} else {
//这里设置两秒的超时时间,如果超过两秒,重置状态
if (time - mTempTime > 2000) {
//给临时时间和点击次数进行初始化
mTempTime = time;
mClickNum = 0;
return;
}
mClickNum++;
mTempTime = time;
//因为一次点击走if语句
if (mClickNum == 4) {
Toast.makeText(MainActivity.this, "已连续点击五次 - 触发:隐藏入口", Toast.LENGTH_SHORT).show();
//给临时时间和点击次数进行初始化
mTempTime = 0;
mClickNum = 0;
}
}
}
});
}
}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:id="@+id/btn_1"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center"
android:text="长按监听 (原生版) - 隐藏入口" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#fb5" />
<TextView
android:id="@+id/btn_2"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center"
android:text="长按时长监听(乞丐版) - 隐藏入口" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#fb5" />
<TextView
android:id="@+id/btn_3"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center"
android:text="长按时长监听(主推:土豪版) - 隐藏入口" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#fb5" />
<TextView
android:id="@+id/btn_4"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center"
android:text="规定时间,点击次数(主推:土豪版) - 隐藏入口" />
LinearLayout>