最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android仿微信文章懸浮窗效果的實(shí)現(xiàn)代碼

 更新時(shí)間:2018年10月09日 15:23:16   作者:24K純帥豆  
這篇文章主要介紹了Android仿微信文章懸浮窗效果的實(shí)現(xiàn)代碼,需要的朋友可以參考下

序言

前些日子跟朋友聊天,朋友Z果粉,前些天更新了微信,說(shuō)微信出了個(gè)好方便的功能啊,我問(wèn)是啥功能啊,看看我大Android有沒(méi)有,他說(shuō)現(xiàn)在閱讀公眾號(hào)文章如果有人給你發(fā)微信你可以把這篇文章當(dāng)作懸浮窗懸浮起來(lái),方便你聊完天不用找繼續(xù)閱讀,聽(tīng)完是不是覺(jué)得這叫啥啊,我大Android微信版不是早就有這個(gè)功能了嗎,我看文章的時(shí)候看到過(guò)有這個(gè)懸浮按鈕,但是我一直沒(méi)有使用過(guò),試了一下還是挺方便的,就想著自己實(shí)現(xiàn)一下這個(gè)功能,下面看圖,大家都習(xí)慣了無(wú)圖言X

image

原理

看完動(dòng)圖我們來(lái)分析一下,如何在每個(gè)頁(yè)面上都存在一個(gè)View呢,有些人可能會(huì)說(shuō),寫在base里面,這樣每次啟動(dòng)一個(gè)新的Activity都要往頁(yè)面上addView一次,性能不好,再說(shuō)了,我們作為一個(gè)優(yōu)秀的程序員能干這種重復(fù)的事嗎,這種方案果斷打回去;既然這樣的話那我們肯定要在全局加了,那么全局是哪呢?相信了解過(guò)Activity源碼的朋友肯定知道,全局可以在Window層加啊,這樣既能一次性搞定,又不影響性能,說(shuō)干就干。

實(shí)現(xiàn)

1、權(quán)限

首先我們要考慮的一個(gè)問(wèn)題就是權(quán)限問(wèn)題,因?yàn)橐m配Android 7.0 8.0,添加懸浮窗是需要申請(qǐng)權(quán)限的,適配的比較全,可以直接拿來(lái)用。這里需要注意的是,為了適配Android 8.0,Window的類型需要配置一下:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
 //Android 8.0
 mLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
 //其他版本
 mLayoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
}

2、添加ViewGroup到Window

判斷好權(quán)限之后,直接添加就可以了

@SuppressLint("CheckResult")
private void showWindow(Context context) {
 mWindowManager = (WindowManager) context.getSystemService(WINDOW_SERVICE);
 mView = LayoutInflater.from(context).inflate(R.layout.article_window, null);

 ImageView ivImage = mView.findViewById(R.id.aw_iv_image);
 String imageUrl = SPUtil.getStringDefault(ARTICLE_IMAGE_URL, "");
 RequestOptions requestOptions = RequestOptions.circleCropTransform();
 requestOptions.placeholder(R.mipmap.ic_launcher_round).error(R.mipmap.ic_launcher_round);
 Glide.with(context).load(imageUrl).apply(requestOptions).into(ivImage);

 initListener(context);

 mLayoutParams = new WindowManager.LayoutParams();
 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
  mLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
 } else {
  mLayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
 }
 mLayoutParams.format = PixelFormat.RGBA_8888; //窗口透明
 mLayoutParams.gravity = Gravity.LEFT | Gravity.TOP; //窗口位置
 mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
 mLayoutParams.width = 200;
 mLayoutParams.height = 200;
 mLayoutParams.x = mWindowManager.getDefaultDisplay().getWidth() - 200;
 mLayoutParams.y = 0;
 mWindowManager.addView(mView, mLayoutParams);
}

3、View的拖拽實(shí)現(xiàn)

借助WindowManager.LayoutParams來(lái)實(shí)現(xiàn),mLayoutParams.x和mLayoutParams.y分別表示mView左上角的橫縱坐標(biāo),所以我們只需要改動(dòng)這兩個(gè)值就行了,當(dāng)ACTION_UP時(shí),計(jì)算當(dāng)前mView的中心點(diǎn)相對(duì)窗口的位置,然后將mView動(dòng)態(tài)滑動(dòng)到窗口左邊或者右邊:

//設(shè)置觸摸滑動(dòng)事件
mView.setOnTouchListener(new View.OnTouchListener() {
 int startX, startY; //起始點(diǎn)
 boolean isMove; //是否在移動(dòng)
 long startTime;
 int finalMoveX; //最后通過(guò)動(dòng)畫(huà)將mView的X軸坐標(biāo)移動(dòng)到finalMoveX
 @Override
 public boolean onTouch(View v, MotionEvent event) {
  switch (event.getAction()) {
   case MotionEvent.ACTION_DOWN:
    startX = (int) event.getX();
    startY = (int) event.getY();
    startTime = System.currentTimeMillis();
    isMove = false;
    return false;
   case MotionEvent.ACTION_MOVE:
    mLayoutParams.x = (int) (event.getRawX() - startX);
    mLayoutParams.y = (int) (event.getRawY() - startY);
    updateViewLayout(); //更新mView 的位置
    return true;
   case MotionEvent.ACTION_UP:
    long curTime = System.currentTimeMillis();
    isMove = curTime - startTime > 100;
    //判斷mView是在Window中的位置,以中間為界
    if (mLayoutParams.x + mView.getMeasuredWidth() / 2 >= mWindowManager.getDefaultDisplay().getWidth() / 2) {
     finalMoveX = mWindowManager.getDefaultDisplay().getWidth() - mView.getMeasuredWidth();
    } else {
     finalMoveX = 0;
    }
    //使用動(dòng)畫(huà)移動(dòng)mView
    ValueAnimator animator = ValueAnimator.ofInt(mLayoutParams.x, finalMoveX).setDuration(Math.abs(mLayoutParams.x - finalMoveX));
    animator.addUpdateListener((ValueAnimator animation) -> {
     mLayoutParams.x = (int) animation.getAnimatedValue();
     updateViewLayout();
    });
    animator.start();
    return isMove;
  }
  return false;
 }
});

4、注意

為了讓W(xué)indow與Activity脫離,這里我們采用Service來(lái)做,通過(guò)Service來(lái)添加和移除View;在權(quán)限申請(qǐng)成功之后我們需要通知Service(其實(shí)是Activity,可能會(huì)有保存數(shù)據(jù)等操作)作相應(yīng)改變(提供一個(gè)接口給Service),然后在Service中使用廣播來(lái)通知Activity;最后一個(gè)需要注意的地方就是我們需要判斷應(yīng)用程序是否在前臺(tái)還是后臺(tái)來(lái)添加或移除Window,這里通過(guò)使用ActivityLifecycleCallbacks來(lái)監(jiān)聽(tīng)Activity在前臺(tái)的數(shù)量來(lái)判斷應(yīng)用程序是在前臺(tái)還是后臺(tái)

class ApplicationLifecycle : Application.ActivityLifecycleCallbacks {
 private var started: Int = 0
 override fun onActivityPaused(activity: Activity?) {
 }
 override fun onActivityResumed(activity: Activity?) {
 }
 override fun onActivityStarted(activity: Activity?) {
  started++
  if (started == 1) {
   Log.e("TAG", "應(yīng)用在前臺(tái)了!!!")
  }
 }
 override fun onActivityDestroyed(activity: Activity?) {
 }
 override fun onActivitySaveInstanceState(activity: Activity?, outState: Bundle?) {
 }
 override fun onActivityStopped(activity: Activity?) {
  started--
  if (started == 0) {
   Log.e("TAG", "應(yīng)用在后臺(tái)了!?。?)
  }
 }
 override fun onActivityCreated(activity: Activity?, savedInstanceState: Bundle?) {
 }
}

本文代碼已傳至Github,有需要的朋友可以下載下來(lái)看看。

總結(jié)

以上所述是小編給大家介紹的Android仿微信文章懸浮窗效果,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!

相關(guān)文章

  • Android Jetpack組件庫(kù)LiveData源碼深入探究

    Android Jetpack組件庫(kù)LiveData源碼深入探究

    LiveData是Jetpack組件的一部分,更多的時(shí)候是搭配ViewModel來(lái)使用,相對(duì)于Observable,LiveData的最大優(yōu)勢(shì)是其具有生命感知的,換句話說(shuō),LiveData可以保證只有在組件( Activity、Fragment、Service)處于活動(dòng)生命周期狀態(tài)的時(shí)候才會(huì)更新數(shù)據(jù)
    2022-09-09
  • Android顯示系統(tǒng)SurfaceFlinger分析

    Android顯示系統(tǒng)SurfaceFlinger分析

    本文詳細(xì)講解了Android顯示系統(tǒng)SurfaceFlinger,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-12-12
  • Android圖表庫(kù)HelloCharts的實(shí)例詳解

    Android圖表庫(kù)HelloCharts的實(shí)例詳解

    這篇文章主要介紹了Android中的圖標(biāo)庫(kù)HelloCharts的一些簡(jiǎn)單使用實(shí)例,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)有一定的參考價(jià)值,需要的可以參考一下
    2022-01-01
  • Android使用Gallery實(shí)現(xiàn)照片拖動(dòng)的特效

    Android使用Gallery實(shí)現(xiàn)照片拖動(dòng)的特效

    這篇文章主要介紹了Android如何使用Gallery實(shí)現(xiàn)照片拖動(dòng)的特效,幫助大家更好的理解和利用Android進(jìn)行開(kāi)發(fā),感興趣的朋友可以了解下
    2021-01-01
  • Android編程實(shí)現(xiàn)向桌面添加快捷方式的方法

    Android編程實(shí)現(xiàn)向桌面添加快捷方式的方法

    這篇文章主要介紹了Android編程實(shí)現(xiàn)向桌面添加快捷方式的方法,結(jié)合實(shí)例形式詳細(xì)分析了Android添加桌面快捷方式的操作技巧,需要的朋友可以參考下
    2016-11-11
  • Android實(shí)時(shí)獲取攝像頭畫(huà)面?zhèn)鬏斨罰C端思路詳解

    Android實(shí)時(shí)獲取攝像頭畫(huà)面?zhèn)鬏斨罰C端思路詳解

    這篇文章主要介紹了Android實(shí)時(shí)獲取攝像頭畫(huà)面?zhèn)鬏斨罰C端思路詳解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-07-07
  • android整數(shù)二分模板徹底解決邊界問(wèn)題

    android整數(shù)二分模板徹底解決邊界問(wèn)題

    這篇文章主要介紹了android整數(shù)二分模板徹底解決邊界問(wèn)題,主要利用android整數(shù)二分模板解決邊界問(wèn)題,需要的朋友可以參考一下,希望對(duì)你有所幫助
    2021-12-12
  • Android 實(shí)現(xiàn)釘釘自動(dòng)打卡功能

    Android 實(shí)現(xiàn)釘釘自動(dòng)打卡功能

    這篇文章主要介紹了Android 實(shí)現(xiàn)釘釘自動(dòng)打卡功能的步驟,幫助大家更好的理解和學(xué)習(xí)使用Android,感興趣的朋友可以了解下
    2021-03-03
  • Kotlin語(yǔ)言中CompileSdkVersion與targetSdkVersion的區(qū)別淺析

    Kotlin語(yǔ)言中CompileSdkVersion與targetSdkVersion的區(qū)別淺析

    這篇文章主要介紹了Kotlin語(yǔ)言中CompileSdkVersion和targetSdkVersion有什么區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧
    2023-02-02
  • Android開(kāi)發(fā)之串口編程原理和實(shí)現(xiàn)方式

    Android開(kāi)發(fā)之串口編程原理和實(shí)現(xiàn)方式

    提到串口編程,就不得不提到JNI,不得不提到JavaAPI中的文件描述符類:FileDescriptor;下面我分別對(duì)JNI、FileDescriptor以及串口的一些知識(shí)點(diǎn)和實(shí)現(xiàn)的源碼進(jìn)行分析說(shuō)明,感興趣的朋友可以了解下
    2013-01-01

最新評(píng)論

河池市| 武隆县| 遂昌县| 鹿泉市| 桦甸市| 庐江县| 林州市| 宁海县| 兴文县| 临高县| 崇义县| 临泉县| 斗六市| 榆中县| 盐源县| 金门县| 奇台县| 纳雍县| 青阳县| 苗栗县| 凤阳县| 牟定县| 监利县| 尖扎县| 彰化县| 将乐县| 简阳市| 睢宁县| 开江县| 科尔| 保靖县| 博客| 东山县| 福海县| 广平县| 泰兴市| 保山市| 西乌珠穆沁旗| 辽阳县| 海安县| 新泰市|