android.support.design.widget.CoordinatorLayout
站在用戶的角度思考問題,與客戶深入溝通,找到輪臺網站設計與輪臺網站推廣的解決方案,憑借多年的經驗,讓設計與互聯網技術結合,創(chuàng)造個性化、用戶體驗好的作品,建站類型包括:網站設計、成都網站制作、企業(yè)官網、英文網站、手機端網站、網站推廣、域名與空間、虛擬空間、企業(yè)郵箱。業(yè)務覆蓋輪臺地區(qū)。
android:layout_width="match_parent"
android:layout_height="match_parent"
其他控件
android.support.design.widget.FloatingActionButton
android:id="@+id/pro_departmeng_fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/pro_button"
android:onClick="onClick"
app:layout_anchor="@id/bc_pro_department"
app:layout_anchorGravity="right|top"
android:layout_marginRight="@dimen/size5"
app:rippleColor="@color/colorPrimary"
app:borderWidth="@dimen/size0"
android:elevation="@dimen/size5"
android:backgroundTint="@color/white"
app:fabSize="mini"/
//初始化
@Bind(R.id.pro_departmeng_fab)
FloatingActionButtonproDepartmengFab;
//監(jiān)聽事件
proDepartmengFab.setOnClickListener(newView.OnClickListener() {
@Override
public voidonClick(View view) {
Toast.makeText(getContext(),"test",Toast.LENGTH_LONG).show();
}
});
四、屬性介紹
1、app:borderWidth=""------------------邊框寬度,通常設置為0 ,用于解決Android 5.X設備上陰影無法正常顯示的問題
2、app:backgroundTint=""---------------按鈕的背景顏色,不設置,默認使用theme中colorAccent的顏色
3、app:rippleColor=""--------------------點擊的邊緣陰影顏色
4、app:elevation=""----------------------邊緣陰影的寬度
5、app:pressedTranslationZ="16dp"-----點擊按鈕時,按鈕邊緣陰影的寬度,通常設置比elevation的數值大
當我們在使用的app的時候,如果需要實時觀測到某個功能的實時進度并且不影響其他的操作的時候或者不影響使用其他應用的時候,系統(tǒng)級的懸浮球是個非常不錯的選擇。
public class QueueUpFloatService extends Service {
/**
* 啟動服務并傳值
*
* @param activity 啟動服務的activity
* @param modeBean 數據對象
*/
public static void launchService(Activity activity, ModeBean modeBean) {
try {
Intent intent =new Intent(activity, QueueUpFloatService.class);
? ? Bundle bundle =new Bundle();
? ? bundle.putSerializable(KEY_MODEL, modeBean);
? ? intent.putExtras(bundle);
? ? activity.startService(intent);
}catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
@Override
public void onCreate() {
super.onCreate();
//加一點簡單的動畫?
buttonScale = (ScaleAnimation) AnimationUtils.loadAnimation(this, R.anim.anim_float);
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
layoutParams =new WindowManager.LayoutParams();
if (Build.VERSION.SDK_INT = Build.VERSION_CODES.O) {
layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
}else {
layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
}
layoutParams.format = PixelFormat.RGBA_8888;
layoutParams.gravity = Gravity.LEFT | Gravity.TOP;
layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | ????????????WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
layoutParams.width = ScreenUtils.dp2px(66);
layoutParams.height = ScreenUtils.dp2px(66);
layoutParams.x = ScreenUtils.getRealWidth() - ScreenUtils.dp2px(60);
layoutParams.y = ScreenUtils.deviceHeight() *2 /3;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
ModeBean modeBean = (ModeBean) intent.getExtras().getSerializable(KEY_MODEL);
LayoutInflater layoutInflater = LayoutInflater.from(this);
floatView = layoutInflater.inflate(R.layout.view_float, null);
RelativeLayout rlFloatParent =floatView.findViewById(R.id.rl_float_parent);
rlFloatParent.startAnimation(buttonScale);
TextView tvIndex =floatView.findViewById(R.id.tv_queue_index);
tvIndex.setText(modeBean.title);
floatView.findViewById(R.id.iv_close_float).setOnClickListener(v - stopSelf());
//修改懸浮球的滑動實現
floatView.setOnTouchListener(new FloatingOnTouchListener());
windowManager.addView(floatView, layoutParams);
return super.onStartCommand(intent, flags, startId);
}
private class FloatingOnTouchListenerimplements View.OnTouchListener {
private int x;
private int y;
private long downTime;
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouch(View view, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downTime = System.currentTimeMillis();
? ? ? ? ? ? ????????x = (int) event.getRawX();
? ? ? ? ? ????????? y = (int) event.getRawY();
break;
? ? ? ????? case MotionEvent.ACTION_MOVE:
int nowX = (int) event.getRawX();
? ? ????????? ? ? ? int nowY = (int) event.getRawY();
? ? ? ????????? ? ? int movedX = nowX -x;
? ? ? ? ????????? ? int movedY = nowY -y;
? ? ? ? ????????? ? x = nowX;
? ? ? ? ? ????????? y = nowY;
? ? ? ? ? ????????? layoutParams.x =layoutParams.x + movedX;
? ? ? ? ? ? ????????layoutParams.y =layoutParams.y + movedY;
? ? ? ? ? ? ? ? ? ? windowManager.updateViewLayout(view, layoutParams);
break;
? ? ? ????? case MotionEvent.ACTION_UP:
/* *
* 這里根據手指按下和抬起的時間差來判斷點擊事件還是滑動事件
* */
? ? ? ? ????????? ? if ((System.currentTimeMillis() -downTime) 200) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? //檢測應用在前臺還是后臺
if (AppUtils.isAppIsInBackground()) {
AppUtils.moveToFront(CloseActivityUtils.activityList.get(CloseActivityUtils.activityList.size() -1).getClass());
? ? ? ? ? ? ? ????????????? } else {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //檢測棧頂是否為SecondActivity 不是就打開SecondActivity
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if (!CloseActivityUtils.activityList.get(CloseActivityUtils.activityList.size() -1)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ????????????????.getClass().getSimpleName().contains("SecondActivity")) {
? ? ? ? ? ? ? ? ? ? ? ? ? ????????? SecondActivity.launchActivity(CloseActivityUtils.activityList.get(CloseActivityUtils.activityList.size() -1));
? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? }
}
break;
? ? ? ? default:
break;
? ? }
? ?return false;
}
}
@Override
public void onDestroy() {
super.onDestroy();
if (null ==floatView) {
return;
? ? ? ? ? ?}
windowManager.removeView(floatView);
? ? ? ? windowManager=null;
}
倉庫地址:
pub 地址:
修改 MainActivity.kt 讓 MainActivity 繼承 qiuxiang.android_window.AndroidWindowActivity :
創(chuàng)建 MainApplication.kt :
修改 AndroidManifest.xml 的 application 新增屬性 android:name=".MainApplication" :
main.dart:
我們需要用 @pragma('vm:entry-point') 聲明一個入口函數,默認函數名是 androidWindow ,當然你可以隨意指定一個,只是調用 open 的時候需要同時指定參數 entryPoint: 。
android_window.dart:
浮窗 app 的寫法就和我們平時寫的 app 沒什么區(qū)別了,如果需要支持窗口拖拽移動,則要在最外層使用 AndroidWindow 。
最終效果:
更完整的示例請參考:
主應用和浮窗都有 post 和 setHandler 方法用于發(fā)送消息以及設置監(jiān)聽處理函數。用法舉例:
主應用發(fā)送消息到浮窗:
浮窗監(jiān)聽并處理主應用消息:
反過來同理。
本文例子實現了點擊顯示懸浮窗口,同時窗口可播放視頻,拖動位置,點擊關閉及返回 APP 頁面,通過例子來講述懸浮窗口實現原理及細節(jié)處理,效果圖如下所示:
關于懸浮窗的一些基本操作到這里就基本結束了,具體的布局內容及操作,歡迎查看具體的源碼實現: Github開發(fā)記錄
歡迎點擊查閱及Star,我也會繼續(xù)補充其它有用的知識及例子在項目上。
歡迎點贊/評論,你們的贊同和鼓勵是我寫作的最大動力!
1、首先打開微信軟件app。
2、進去后主頁后找到右下角的我的。
3、然后點擊一下。
4、進去我的以后找到設置并點擊進去。
5、找到顯示懸浮窗點擊一下并選擇小程序支付就開啟顯示懸浮窗了。