Android實(shí)現(xiàn)桌面懸浮窗、蒙板效果實(shí)例代碼
現(xiàn)在很多安全類的軟件,比如360手機(jī)助手,百度手機(jī)助手等等,都有一個懸浮窗,可以飄浮在桌面上,方便用戶使用一些常用的操作。
今天這篇文章,就是介紹如何實(shí)現(xiàn)桌面懸浮窗效果的。
首先,看一下效果圖。

懸浮窗一共分為兩個部分,一個是平常顯示的小窗口,另外一個是點(diǎn)擊小窗口顯示出來的二級懸浮窗口。
首先,先看一下這個項(xiàng)目的目錄結(jié)構(gòu)。

最關(guān)鍵的就是紅框內(nèi)的四個類。
首先,F(xiàn)loatWindowService是一個后臺的服務(wù)類,主要負(fù)責(zé)在后臺不斷的刷新桌面上的小懸浮窗口,否則會導(dǎo)致更換界面之后,懸浮窗口也會隨之消失,因此需要不斷的刷新。下面是實(shí)現(xiàn)代碼。
package com.qust.floatwindow;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
/**
* 懸浮窗后臺服務(wù)
*
* @author zhaokaiqiang
*
*/
public class FloatWindowService extends Service {
public static final String LAYOUT_RES_ID = "layoutResId";
public static final String ROOT_LAYOUT_ID = "rootLayoutId";
// 用于在線程中創(chuàng)建/移除/更新懸浮窗
private Handler handler = new Handler();
private Context context;
private Timer timer;
// 小窗口布局資源id
private int layoutResId;
// 布局根布局id
private int rootLayoutId;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
context = this;
layoutResId = intent.getIntExtra(LAYOUT_RES_ID, 0);
rootLayoutId = intent.getIntExtra(ROOT_LAYOUT_ID, 0);
if (layoutResId == 0 || rootLayoutId == 0) {
throw new IllegalArgumentException(
"layoutResId or rootLayoutId is illegal");
}
if (timer == null) {
timer = new Timer();
// 每500毫秒就執(zhí)行一次刷新任務(wù)
timer.scheduleAtFixedRate(new RefreshTask(), 0, 500);
}
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
// Service被終止的同時也停止定時器繼續(xù)運(yùn)行
timer.cancel();
timer = null;
}
private class RefreshTask extends TimerTask {
@Override
public void run() {
// 當(dāng)前界面沒有懸浮窗顯示,則創(chuàng)建懸浮
if (!FloatWindowManager.getInstance(context).isWindowShowing()) {
handler.post(new Runnable() {
@Override
public void run() {
FloatWindowManager.getInstance(context)
.createSmallWindow(context, layoutResId,
rootLayoutId);
}
});
}
}
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
除了后臺服務(wù)之外,我們還需要兩個自定義的布局,分別是FloatWindowSmallView和FloatWindowBigView,這兩個自定義的布局,主要負(fù)責(zé)懸浮窗的前臺顯示,我們分別看一下代碼實(shí)現(xiàn)。
首先是FloatWindowSmallView類的實(shí)現(xiàn)。
package com.qust.floatwindow;
import java.lang.reflect.Field;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.PixelFormat;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.qust.demo.ScreenUtils;
import com.qust.floatingwindow.R;
/**
* 小懸浮窗,用于初始顯示
*
* @author zhaokaiqiang
*
*/
public class FloatWindowSmallView extends LinearLayout {
// 小懸浮窗的寬
public int viewWidth;
// 小懸浮窗的高
public int viewHeight;
// 系統(tǒng)狀態(tài)欄的高度
private static int statusBarHeight;
// 用于更新小懸浮窗的位置
private WindowManager windowManager;
// 小懸浮窗的布局參數(shù)
public WindowManager.LayoutParams smallWindowParams;
// 記錄當(dāng)前手指位置在屏幕上的橫坐標(biāo)
private float xInScreen;
// 記錄當(dāng)前手指位置在屏幕上的縱坐標(biāo)
private float yInScreen;
// 記錄手指按下時在屏幕上的橫坐標(biāo),用來判斷單擊事件
private float xDownInScreen;
// 記錄手指按下時在屏幕上的縱坐標(biāo),用來判斷單擊事件
private float yDownInScreen;
// 記錄手指按下時在小懸浮窗的View上的橫坐標(biāo)
private float xInView;
// 記錄手指按下時在小懸浮窗的View上的縱坐標(biāo)
private float yInView;
// 單擊接口
private OnClickListener listener;
/**
* 構(gòu)造函數(shù)
*
* @param context
* 上下文對象
* @param layoutResId
* 布局資源id
* @param rootLayoutId
* 根布局id
*/
public FloatWindowSmallView(Context context, int layoutResId,
int rootLayoutId) {
super(context);
windowManager = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
LayoutInflater.from(context).inflate(layoutResId, this);
View view = findViewById(rootLayoutId);
viewWidth = view.getLayoutParams().width;
viewHeight = view.getLayoutParams().height;
statusBarHeight = getStatusBarHeight();
TextView percentView = (TextView) findViewById(R.id.percent);
percentView.setText("懸浮窗");
smallWindowParams = new WindowManager.LayoutParams();
// 設(shè)置顯示類型為phone
smallWindowParams.type = WindowManager.LayoutParams.TYPE_PHONE;
// 顯示圖片格式
smallWindowParams.format = PixelFormat.RGBA_8888;
// 設(shè)置交互模式
smallWindowParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
// 設(shè)置對齊方式為左上
smallWindowParams.gravity = Gravity.LEFT | Gravity.TOP;
smallWindowParams.width = viewWidth;
smallWindowParams.height = viewHeight;
smallWindowParams.x = ScreenUtils.getScreenWidth(context);
smallWindowParams.y = ScreenUtils.getScreenHeight(context) / 2;
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
// 手指按下時記錄必要的數(shù)據(jù),縱坐標(biāo)的值都減去狀態(tài)欄的高度
case MotionEvent.ACTION_DOWN:
// 獲取相對與小懸浮窗的坐標(biāo)
xInView = event.getX();
yInView = event.getY();
// 按下時的坐標(biāo)位置,只記錄一次
xDownInScreen = event.getRawX();
yDownInScreen = event.getRawY() - statusBarHeight;
break;
case MotionEvent.ACTION_MOVE:
// 時時的更新當(dāng)前手指在屏幕上的位置
xInScreen = event.getRawX();
yInScreen = event.getRawY() - statusBarHeight;
// 手指移動的時候更新小懸浮窗的位置
updateViewPosition();
break;
case MotionEvent.ACTION_UP:
// 如果手指離開屏幕時,按下坐標(biāo)與當(dāng)前坐標(biāo)相等,則視為觸發(fā)了單擊事件
if (xDownInScreen == event.getRawX()
&& yDownInScreen == (event.getRawY() - getStatusBarHeight())) {
if (listener != null) {
listener.click();
}
}
break;
}
return true;
}
/**
* 設(shè)置單擊事件的回調(diào)接口
*/
public void setOnClickListener(OnClickListener listener) {
this.listener = listener;
}
/**
* 更新小懸浮窗在屏幕中的位置
*/
private void updateViewPosition() {
smallWindowParams.x = (int) (xInScreen - xInView);
smallWindowParams.y = (int) (yInScreen - yInView);
windowManager.updateViewLayout(this, smallWindowParams);
}
/**
* 獲取狀態(tài)欄的高度
*
* @return
*/
private int getStatusBarHeight() {
try {
Class<?> c = Class.forName("com.android.internal.R$dimen");
Object o = c.newInstance();
Field field = c.getField("status_bar_height");
int x = (Integer) field.get(o);
return getResources().getDimensionPixelSize(x);
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
/**
* 單擊接口
*
* @author zhaokaiqiang
*
*/
public interface OnClickListener {
public void click();
}
}
在這個類里面,主要的工作是實(shí)現(xiàn)懸浮窗口在桌面前端的實(shí)現(xiàn),還有就是位置的移動和單擊事件的判斷以及處理。這里使用的是主要是WindowManager類的一些方法和屬性,下一篇會詳細(xì)說明,這篇只說實(shí)現(xiàn)。
除了小懸浮窗之外,點(diǎn)擊之后彈出的二級懸浮窗也是類似的方式添加到桌面上,下面是二級懸浮窗的代碼。
package com.qust.floatwindow;
import android.content.Context;
import android.graphics.PixelFormat;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.qust.demo.ScreenUtils;
import com.qust.floatingwindow.R;
public class FloatWindowBigView extends LinearLayout {
// 記錄大懸浮窗的寬
public int viewWidth;
// 記錄大懸浮窗的高
public int viewHeight;
public WindowManager.LayoutParams bigWindowParams;
private Context context;
public FloatWindowBigView(Context context) {
super(context);
this.context = context;
LayoutInflater.from(context).inflate(R.layout.float_window_big, this);
View view = findViewById(R.id.big_window_layout);
viewWidth = view.getLayoutParams().width;
viewHeight = view.getLayoutParams().height;
bigWindowParams = new WindowManager.LayoutParams();
// 設(shè)置顯示的位置,默認(rèn)的是屏幕中心
bigWindowParams.x = ScreenUtils.getScreenWidth(context) / 2 - viewWidth
/ 2;
bigWindowParams.y = ScreenUtils.getScreenHeight(context) / 2
- viewHeight / 2;
bigWindowParams.type = WindowManager.LayoutParams.TYPE_PHONE;
bigWindowParams.format = PixelFormat.RGBA_8888;
// 設(shè)置交互模式
bigWindowParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
bigWindowParams.gravity = Gravity.LEFT | Gravity.TOP;
bigWindowParams.width = viewWidth;
bigWindowParams.height = viewHeight;
initView();
}
private void initView() {
TextView tv_back = (TextView) findViewById(R.id.tv_back);
tv_back.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
FloatWindowManager.getInstance(context).removeBigWindow();
}
});
}
}
這些基本的類建立起來之后,剩下的就是最重要的類FloatWindowManager的實(shí)現(xiàn)。這個類實(shí)現(xiàn)的就是對懸浮窗的操作。
package com.qust.floatwindow;
import android.content.Context;
import android.content.Intent;
import android.view.WindowManager;
/**
* 懸浮窗管理器
*
* @author zhaokaiqiang
*
*/
public class FloatWindowManager {
// 小懸浮窗對象
private FloatWindowSmallView smallWindow;
// 大懸浮窗對象
private FloatWindowBigView bigWindow;
// 用于控制在屏幕上添加或移除懸浮窗
private WindowManager mWindowManager;
// FloatWindowManager的單例
private static FloatWindowManager floatWindowManager;
// 上下文對象
private Context context;
private FloatWindowManager(Context context) {
this.context = context;
}
public static FloatWindowManager getInstance(Context context) {
if (floatWindowManager == null) {
floatWindowManager = new FloatWindowManager(context);
}
return floatWindowManager;
}
/**
* 創(chuàng)建小懸浮窗
*
* @param context
* 必須為應(yīng)用程序的Context.
*/
public void createSmallWindow(Context context, int layoutResId,
int rootLayoutId) {
WindowManager windowManager = getWindowManager();
if (smallWindow == null) {
smallWindow = new FloatWindowSmallView(context, layoutResId,
rootLayoutId);
windowManager.addView(smallWindow, smallWindow.smallWindowParams);
}
}
/**
* 將小懸浮窗從屏幕上移除
*
* @param context
*/
public void removeSmallWindow() {
if (smallWindow != null) {
WindowManager windowManager = getWindowManager();
windowManager.removeView(smallWindow);
smallWindow = null;
}
}
public void setOnClickListener(FloatWindowSmallView.OnClickListener listener) {
if (smallWindow != null) {
smallWindow.setOnClickListener(listener);
}
}
/**
* 創(chuàng)建大懸浮窗
*
* @param context
* 必須為應(yīng)用程序的Context.
*/
public void createBigWindow(Context context) {
WindowManager windowManager = getWindowManager();
if (bigWindow == null) {
bigWindow = new FloatWindowBigView(context);
windowManager.addView(bigWindow, bigWindow.bigWindowParams);
}
}
/**
* 將大懸浮窗從屏幕上移除
*
* @param context
*/
public void removeBigWindow() {
if (bigWindow != null) {
WindowManager windowManager = getWindowManager();
windowManager.removeView(bigWindow);
bigWindow = null;
}
}
public void removeAll() {
context.stopService(new Intent(context, FloatWindowService.class));
removeSmallWindow();
removeBigWindow();
}
/**
* 是否有懸浮窗顯示(包括小懸浮窗和大懸浮)
*
* @return 有懸浮窗顯示在桌面上返回true,沒有的話返回false
*/
public boolean isWindowShowing() {
return smallWindow != null || bigWindow != null;
}
/**
* 如果WindowManager還未創(chuàng)建,則創(chuàng)建新的WindowManager返回。否則返回當(dāng)前已創(chuàng)建的WindowManager
*
* @param context
* @return
*/
private WindowManager getWindowManager() {
if (mWindowManager == null) {
mWindowManager = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
}
return mWindowManager;
}
}
還有個獲取屏幕寬高的幫助類。
package com.qust.demo;
import android.content.Context;
import android.view.WindowManager;
/**
* 屏幕幫助類
*
* @author zhaokaiqiang
*
*/
public class ScreenUtils {
/**
* 獲取屏幕寬度
*
* @return
*/
@SuppressWarnings("deprecation")
public static int getScreenWidth(Context context) {
return ((WindowManager) context
.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay()
.getWidth();
}
/**
* 獲取屏幕寬度
*
* @return
*/
@SuppressWarnings("deprecation")
public static int getScreenHeight(Context context) {
return ((WindowManager) context
.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay()
.getHeight();
}
}
完成這些,我們就可以直接用了。
package com.qust.demo;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import com.qust.floatingwindow.R;
import com.qust.floatwindow.FloatWindowManager;
import com.qust.floatwindow.FloatWindowService;
import com.qust.floatwindow.FloatWindowSmallView.OnClickListener;
/**
* 示例
*
* @ClassName: com.qust.demo.MainActivity
* @Description:
* @author zhaokaiqiang
* @date 2014-10-23 下午11:30:13
*
*/
public class MainActivity extends Activity {
private FloatWindowManager floatWindowManager;
private Context context;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
floatWindowManager = FloatWindowManager.getInstance(context);
}
/**
* 顯示小窗口
*
* @param view
*/
public void show(View view) {
// 需要傳遞小懸浮窗布局,以及根布局的id,啟動后臺服務(wù)
Intent intent = new Intent(context, FloatWindowService.class);
intent.putExtra(FloatWindowService.LAYOUT_RES_ID,
R.layout.float_window_small);
intent.putExtra(FloatWindowService.ROOT_LAYOUT_ID,
R.id.small_window_layout);
startService(intent);
}
/**
* 顯示二級懸浮窗
*
* @param view
*/
public void showBig(View view) {
// 設(shè)置小懸浮窗的單擊事件
floatWindowManager.setOnClickListener(new OnClickListener() {
@Override
public void click() {
floatWindowManager.createBigWindow(context);
}
});
}
/**
* 移除所有的懸浮窗
*
* @param view
*/
public void remove(View view) {
floatWindowManager.removeAll();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// 返回鍵移除二級懸浮窗
if (keyCode == KeyEvent.KEYCODE_BACK
&& event.getAction() == KeyEvent.ACTION_DOWN) {
floatWindowManager.removeBigWindow();
return true;
}
return super.onKeyDown(keyCode, event);
}
}
項(xiàng)目下載地址:https://github.com/ZhaoKaiQiang/FloatWindow
在上面文章中,我們介紹了如何實(shí)現(xiàn)桌面懸浮窗口,在這個效果的實(shí)現(xiàn)過程中,最重要的一個類就是WindowManager,今天這篇文章,將對WindowManager的使用進(jìn)行介紹,并且實(shí)現(xiàn)一個使用WindowManager來實(shí)現(xiàn)用戶打開APP,顯示首次使用教學(xué)蒙板的效果。
WindowManager類實(shí)現(xiàn)了ViewManager接口,ViewManager接口允許我們在Activity上添加或者是移除view,因此WindowManager也允許我們在Activity上進(jìn)行View的添加和移除操作。
我們可以通過下面的方法獲取一個WindowManager對象
Context.getSystemService(Context.WINDOW_SERVICE)
在Activity之中,我們可以直接通過getWindowManager()獲取到一個WindowManager對象。
每一個WindowManager實(shí)例都被綁定到一個獨(dú)有的Display對象上面,如果我們想獲取不同Display的WindowManager對象,我們可以通過createDisplayContext(Display)獲取到這個Display的Context對象,然后使用上面的方法,也可以獲取到一個WindowManager對象。
我們在使用WindowManager類的時候,通常使用下面的幾個方法:
windowManager.addView(View,WindowManager.LayoutParam); windowManager.removeView(); windowManager.getDefaultDisplay();
windowManager.addView()方法用來向當(dāng)前的窗口上添加View對象,需要接受兩個參數(shù),View是要添加到窗口的View對象,而WindowManager.LayoutParam則是添加的窗口的參數(shù),在上一篇添加懸浮窗的操作的時候,需要對LayoutParam設(shè)置很多參數(shù),下面我們看一下常用的設(shè)置
// 設(shè)置LayoutParams參數(shù) LayoutParams params = new WindowManager.LayoutParams(); //設(shè)置顯示的類型,TYPE_PHONE指的是來電話的時候會被覆蓋,其他時候會在最前端,顯示位置在stateBar下面,其他更多的值請查閱文檔 params.type = WindowManager.LayoutParams.TYPE_PHONE; //設(shè)置顯示格式 params.format = PixelFormat.RGBA_8888; //設(shè)置對齊方式 params.gravity = Gravity.LEFT | Gravity.TOP; //設(shè)置寬高 params.width = ScreenUtils.getScreenWidth(this); params.height = ScreenUtils.getScreenHeight(this); //設(shè)置顯示的位置 params.x; params.y;
設(shè)置好LayoutParam之后,我們就可以通過windowManager.addView(View,WindowManager.LayoutParam)將View添加到窗口之上,不過,我們需要申明權(quán)限
<uses-permissionAndroid:name="android.permission.SYSTEM_ALERT_WINDOW"/>
添加完成之后,我們就可以在窗口上看到我們添加的View對象了。如果我們想將添加的View移除,我們只需要調(diào)用windowManager.removeView()即可,參數(shù)就是我們前面使用的View對象,使用很簡單。除了這個方法,還有個windowManager.removeViewImmediate(),也可以將View移除,但是文檔中說,這個方法并不是給一般程序調(diào)用的,因此需要小心使用,我們開發(fā)的都屬于一般程序,建議不要使用這個方法。
除了這兩個方法之外,我們最常用的另外一個方法就是windowManager.getDefaultDisplay(),通過這個方法,我們可以獲取到當(dāng)前界面的Display的一個對象,然后我們就可以獲取到當(dāng)前屏幕的一些參數(shù),比如說寬高。
下面是我常用的一個工具類。
package com.qust.teachmask;
import android.content.Context;
import android.view.WindowManager;
/**
* 屏幕幫助類
*
* @author zhaokaiqiang
*
*/
public class ScreenUtils {
/**
* 獲取屏幕寬度
*
* @return
*/
@SuppressWarnings("deprecation")
public static int getScreenWidth(Context context) {
return ((WindowManager) context
.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay()
.getWidth();
}
/**
* 獲取屏幕寬度
*
* @return
*/
@SuppressWarnings("deprecation")
public static int getScreenHeight(Context context) {
return ((WindowManager) context
.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay()
.getHeight();
}
}
知道上面這些之后,我們就可以實(shí)現(xiàn)教學(xué)模板效果了,首先看效果圖。

下面是代碼實(shí)現(xiàn)
package com.qust.teachmask;
import android.app.Activity;
import android.graphics.PixelFormat;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
public class MainActivity extends Activity {
private ImageView img;
private WindowManager windowManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
windowManager = getWindowManager();
// 動態(tài)初始化圖層
img = new ImageView(this);
img.setLayoutParams(new LayoutParams(
android.view.ViewGroup.LayoutParams.MATCH_PARENT,
android.view.ViewGroup.LayoutParams.MATCH_PARENT));
img.setScaleType(ScaleType.FIT_XY);
img.setImageResource(R.drawable.guide);
// 設(shè)置LayoutParams參數(shù)
LayoutParams params = new WindowManager.LayoutParams();
// 設(shè)置顯示的類型,TYPE_PHONE指的是來電話的時候會被覆蓋,其他時候會在最前端,顯示位置在stateBar下面,其他更多的值請查閱文檔
params.type = WindowManager.LayoutParams.TYPE_PHONE;
// 設(shè)置顯示格式
params.format = PixelFormat.RGBA_8888;
// 設(shè)置對齊方式
params.gravity = Gravity.LEFT | Gravity.TOP;
// 設(shè)置寬高
params.width = ScreenUtils.getScreenWidth(this);
params.height = ScreenUtils.getScreenHeight(this);
// 添加到當(dāng)前的窗口上
windowManager.addView(img, params);
// 點(diǎn)擊圖層之后,將圖層移除
img.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
windowManager.removeView(img);
}
});
}
}
本文非原創(chuàng),轉(zhuǎn)載于:http://blog.csdn.net/zhaokaiqiang1992
以上所述是小編給大家介紹的Android實(shí)現(xiàn)桌面懸浮窗、蒙板效果實(shí)例代碼,希望對大家有所幫助!
- android 添加隨意拖動的桌面懸浮窗口
- 不依賴于Activity的Android全局懸浮窗的實(shí)現(xiàn)
- Android 懸浮窗權(quán)限各機(jī)型各系統(tǒng)適配大全(總結(jié))
- Android應(yīng)用內(nèi)懸浮窗的實(shí)現(xiàn)方案示例
- Android實(shí)現(xiàn)類似360,QQ管家那樣的懸浮窗
- Android實(shí)現(xiàn)類似qq微信消息懸浮窗通知功能
- Android 8.0如何完美適配全局dialog懸浮窗彈出
- Android懸浮窗屏蔽懸浮窗外部所有的點(diǎn)擊事件的實(shí)例代碼
- Android 獲取判斷是否有懸浮窗權(quán)限的方法
- android仿華為手機(jī)懸浮窗設(shè)計(jì)
相關(guān)文章
詳解Android通過修改配置文件設(shè)置wifi密碼
這篇文章主要介紹了詳解Android通過修改配置文件設(shè)置wifi密碼的相關(guān)資料,需要的朋友可以參考下2017-07-07
基于Flutter實(shí)現(xiàn)轉(zhuǎn)場動效的示例代碼
動畫經(jīng)常會用于場景切換,比如滑動,縮放,尺寸變化。Flutter?提供了Transition系列的動畫組件,可以讓場景轉(zhuǎn)換動畫變得更加簡單。本文整理了常用的Transition組件的應(yīng)用,需要的可以參考一下2022-05-05
Android XmlResourceParser出錯解決辦法
這篇文章主要介紹了Android XmlResourceParser出錯解決辦法的相關(guān)資料,需要的朋友可以參考下2017-05-05
Android使用socket創(chuàng)建簡單TCP連接的方法
這篇文章主要介紹了Android使用socket創(chuàng)建簡單TCP連接的方法,結(jié)合實(shí)例形式詳細(xì)分析了Android使用socket創(chuàng)建TCP連接的具體步驟與實(shí)現(xiàn)技巧,需要的朋友可以參考下2016-04-04
android.enableD8.desugaring?=?false引發(fā)問題解決
這篇文章主要為大家介紹了android.enableD8.desugaring?=?false引發(fā)問題解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03
Android獲取RecyclerView滑動距離方法詳細(xì)講解
RecyclerView是Android一個更強(qiáng)大的控件,其不僅可以實(shí)現(xiàn)和ListView同樣的效果,還有優(yōu)化了ListView中的各種不足。其可以實(shí)現(xiàn)數(shù)據(jù)縱向滾動,也可以實(shí)現(xiàn)橫向滾動(ListView做不到橫向滾動)。接下來講解RecyclerView的用法2023-01-01
Android使用post方式上傳圖片到服務(wù)器的方法
這篇文章主要介紹了Android使用post方式上傳圖片到服務(wù)器的方法,結(jié)合實(shí)例形式分析了Android文件傳輸?shù)南嚓P(guān)技巧,需要的朋友可以參考下2016-03-03

