在開發中其實不論前臺、後臺都會留一些後門,方便管理人員操作(有點超級權限的意思),但是這樣的入口我們又不能讓用戶直接看到,所以就有一些芝麻開門的操作 ~
今天真是個好日子啊 - 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);
}
}
};
});
}
}
MainActivity
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;
}
}
}
});
}
}
activity_main
<?xml version="1.0" encoding="utf-8"?>
<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>