Android手勢(shì)ImageView三部曲 第二部
廢話(huà)不多說(shuō)了,還記得上一節(jié)Android手勢(shì)ImageView三部曲(一)最后我們提及的那個(gè)框架么?這一節(jié)我們重點(diǎn)了掌握一下GestureDetector這個(gè)類(lèi)相關(guān)的屬性方法。
一、那么GestureDetector是干嘛的呢?
顧名思義,字面意思就是“手勢(shì)檢測(cè)器“的意思,還記得我們上一節(jié)中實(shí)現(xiàn)的GestureImageView么?我們?cè)趏nTouchEvent中檢測(cè)到了各種個(gè)樣的手勢(shì)(手指按下、抬起、什么時(shí)候?qū)儆谕献?、什么時(shí)候?qū)儆诳s放)都是通過(guò)我們的計(jì)算得到的,但是有了GestureDetector這個(gè)類(lèi)后,我們不需要自己做判斷現(xiàn)在是什么手勢(shì)了,GestureDetector會(huì)幫我們做好判斷,完了后通過(guò)回調(diào)函數(shù)告訴你,就像官網(wǎng)所說(shuō)的(This class should only be used with MotionEvents reported via touch (don't use for trackball events).)這個(gè)類(lèi)僅僅是通過(guò)觸碰檢查事件的,而不是用于跟蹤事件的,我檢測(cè)到了事件,然后告訴你,至于你需要怎么處理這個(gè)事件,那就是你自己的事了。
GestureDetector的一些具體的api大家可以去查看谷歌官方文檔或啟艦大神的博客:
https://developer.android.google.cn/reference/android/view/GestureDetector.html
Android手勢(shì)識(shí)別器GestureDetector使用詳解
說(shuō)了這么多估計(jì)你都有點(diǎn)累了,下面讓我們看看具體怎么使用:
偷一下懶,我就直接用 Android手勢(shì)ImageView三部曲(一)
中的MatrixImageView類(lèi)改改代碼了:
public class MatrixImageView extends ImageView { private static final int MODE_NONE = 190; private static final int MODE_DRAG = 468; private static final int MODE_ZOOM = 685; private int mode; private float startX, startY; private float midX, midY; private Matrix currMatrix, savedMatrix; private float preRotate, rotate; private float preSpacing; private GestureDetector detector; public MatrixImageView(Context context, AttributeSet attrs) { super(context, attrs); initView(); detector=new GestureDetector(context,onGestureListener); } private void initView() { mode = MODE_NONE; currMatrix = new Matrix(); savedMatrix = new Matrix(); DisplayMetrics dm = getResources().getDisplayMetrics(); Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.test); bitmap = Bitmap.createScaledBitmap(bitmap, dm.widthPixels, dm.heightPixels, true); setImageBitmap(bitmap); } @Override public boolean onTouchEvent(MotionEvent event) { return detector.onTouchEvent(event); } private GestureDetector.SimpleOnGestureListener onGestureListener=new GestureDetector.SimpleOnGestureListener(){ @Override public boolean onSingleTapUp(MotionEvent e) { Log.e("TAG", "====onSingleTapUp====="); return super.onSingleTapUp(e); } @Override public void onLongPress(MotionEvent e) { Log.e("TAG", "====onLongPress====="); super.onLongPress(e); } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { Log.e("TAG", "====onScroll====="); Log.e("TAG", "distanceX===>"+distanceX); Log.e("TAG", "distanceY===>"+distanceY); return super.onScroll(e1, e2, distanceX, distanceY); } @Override public void onShowPress(MotionEvent e) { Log.e("TAG", "====onShowPress====="); super.onShowPress(e); } @Override public boolean onDown(MotionEvent e) { Log.e("TAG", "====onDown====="); return true; } @Override public boolean onDoubleTap(MotionEvent e) { Log.e("TAG", "====onDoubleTap====="); return super.onDoubleTap(e); } @Override public boolean onDoubleTapEvent(MotionEvent e) { Log.e("TAG", "====onDoubleTapEvent====="); return super.onDoubleTapEvent(e); } @Override public boolean onSingleTapConfirmed(MotionEvent e) { Log.e("TAG", "====onSingleTapConfirmed====="); return super.onSingleTapConfirmed(e); } @Override public boolean onContextClick(MotionEvent e) { Log.e("TAG", "====onContextClick====="); return super.onContextClick(e); } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { Log.e("TAG", "====onFling====="); Log.e("TAG", "velocityX===>"+velocityX); Log.e("TAG", "velocityY===>"+velocityY); return super.onFling(e1, e2, velocityX, velocityY); } }; }
首先我們?cè)跇?gòu)造方法中創(chuàng)建一個(gè)手勢(shì)監(jiān)測(cè)器的對(duì)象GestureDetector:
public MatrixImageView(Context context, AttributeSet attrs) { super(context, attrs); initView(); detector=new GestureDetector(context,onGestureListener); }
GestureDetector既然是監(jiān)聽(tīng)我們的手勢(shì)的工具類(lèi),那我們是不是得把我們得手勢(shì)交給它呢? 是的?。?于是我們?cè)趏nTouchEvent中把事件交給GestureDetector:
@Override public boolean onTouchEvent(MotionEvent event) { return detector.onTouchEvent(event); }
那我們把事件交給了GestureDetector,GestureDetector處理完畢后我們?cè)趺粗滥兀?還記得我們創(chuàng)建GestureDetector對(duì)象的時(shí)候傳遞的參數(shù)嗎?
detector=new GestureDetector(context,onGestureListener);
我們傳遞給了GestureDetector一個(gè)onGestureListener對(duì)象,GestureDetector檢查完畢手勢(shì)后,會(huì)調(diào)用onGestureListener中的方法進(jìn)行回調(diào),我們只需要在onGestureListener對(duì)象的相應(yīng)方法中作出處理就可以了:
private GestureDetector.SimpleOnGestureListener onGestureListener=new GestureDetector.SimpleOnGestureListener(){ @Override public boolean onSingleTapUp(MotionEvent e) { Log.e(“TAG”, “====onSingleTapUp=====”); return super.onSingleTapUp(e); } @Override public void onLongPress(MotionEvent e) { Log.e("TAG", "====onLongPress====="); super.onLongPress(e); } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { Log.e("TAG", "====onScroll====="); Log.e("TAG", "distanceX===>"+distanceX); Log.e("TAG", "distanceY===>"+distanceY); return super.onScroll(e1, e2, distanceX, distanceY); } @Override public void onShowPress(MotionEvent e) { Log.e("TAG", "====onShowPress====="); super.onShowPress(e); } @Override public boolean onDown(MotionEvent e) { Log.e("TAG", "====onDown====="); return super.onDown(e); } @Override public boolean onDoubleTap(MotionEvent e) { Log.e("TAG", "====onDoubleTap====="); return super.onDoubleTap(e); } @Override public boolean onDoubleTapEvent(MotionEvent e) { Log.e("TAG", "====onDoubleTapEvent====="); return super.onDoubleTapEvent(e); } @Override public boolean onSingleTapConfirmed(MotionEvent e) { Log.e("TAG", "====onSingleTapConfirmed====="); return super.onSingleTapConfirmed(e); } @Override public boolean onContextClick(MotionEvent e) { Log.e("TAG", "====onContextClick====="); return super.onContextClick(e); } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { Log.e("TAG", "====onFling====="); Log.e("TAG", "velocityX===>"+velocityX); Log.e("TAG", "velocityY===>"+velocityY); return super.onFling(e1, e2, velocityX, velocityY); } };
我們先不管其中方法啥時(shí)候調(diào)用,我們先重寫(xiě)它的所有方法,然后打上log,看看我們手指操作后相應(yīng)的回調(diào),于是我們運(yùn)行代碼:
是的,沒(méi)錯(cuò)!就只是一張圖片,因?yàn)槲覀円仓皇秋@示了一張圖片:
我們輕輕的點(diǎn)擊一下屏幕:
03-02 20:47:41.367 1798-1798/com.leo.gestureimageview E/TAG: ====onDown=====
03-02 20:47:41.466 1798-1798/com.leo.gestureimageview E/TAG: ====onShowPress=====
03-02 20:47:41.967 1798-1798/com.leo.gestureimageview E/TAG: ====onLongPress=====
輕輕的點(diǎn)擊一下屏幕:
我們可以看到log執(zhí)行順序:onDown->onShowPress->onLongPress
我們點(diǎn)擊屏幕按下,然后過(guò)一會(huì)再放開(kāi):
03-02 21:51:27.121 17138-17138/com.leo.gestureimageview E/TAG: ====onDown=====
03-02 21:51:27.222 17138-17138/com.leo.gestureimageview E/TAG: ====onShowPress=====
03-02 21:51:27.722 17138-17138/com.leo.gestureimageview E/TAG: ====onLongPress=====
我們滑動(dòng)一下手指:
03-02 21:51:27.121 17138-17138/com.leo.gestureimageview E/TAG: ====onDown=====
03-02 21:51:27.222 17138-17138/com.leo.gestureimageview E/TAG: ====onShowPress=====
03-02 21:51:27.722 17138-17138/com.leo.gestureimageview E/TAG: ====onLongPress=====
不管我們?cè)趺礃硬僮?,打印的log總是這三個(gè)方法? 這是咋回事呢? 如果看到這里你有疑問(wèn)的話(huà),那我告訴你,你Android事件傳遞機(jī)制掌握的還不是很好,為什么這么說(shuō)呢?? 下面我們帶著疑問(wèn)看看源碼:
猜都可以猜到GestureDetector處理手勢(shì)的代碼肯定在onTouchEvent方法中,那么我們看一下onTouchEvent方法:
public boolean onTouchEvent(MotionEvent ev) { if (mDoubleTapListener != null) { boolean hadTapMessage = mHandler.hasMessages(TAP); if (hadTapMessage) mHandler.removeMessages(TAP); if ((mCurrentDownEvent != null) && (mPreviousUpEvent != null) && hadTapMessage && isConsideredDoubleTap(mCurrentDownEvent, mPreviousUpEvent, ev)) { // This is a second tap mIsDoubleTapping = true; // Give a callback with the first tap of the double-tap handled |= mDoubleTapListener.onDoubleTap(mCurrentDownEvent); // Give a callback with down event of the double-tap handled |= mDoubleTapListener.onDoubleTapEvent(ev); } else { // This is a first tap mHandler.sendEmptyMessageDelayed(TAP, DOUBLE_TAP_TIMEOUT); } } mDownFocusX = mLastFocusX = focusX; mDownFocusY = mLastFocusY = focusY; if (mCurrentDownEvent != null) { mCurrentDownEvent.recycle(); } mCurrentDownEvent = MotionEvent.obtain(ev); mAlwaysInTapRegion = true; mAlwaysInBiggerTapRegion = true; mStillDown = true; mInLongPress = false; mDeferConfirmSingleTap = false; if (mIsLongpressEnabled) { mHandler.removeMessages(LONG_PRESS); mHandler.sendEmptyMessageAtTime(LONG_PRESS, mCurrentDownEvent.getDownTime() + TAP_TIMEOUT + LONGPRESS_TIMEOUT); } mHandler.sendEmptyMessageAtTime(SHOW_PRESS, mCurrentDownEvent.getDownTime() + TAP_TIMEOUT); handled |= mListener.onDown(ev); break; }
代碼太多了,那為什么我們只收到了onDown、onShowPress、onLongPress這三個(gè)方法的回調(diào)呢?
我們知道,當(dāng)我們手指剛按下屏幕的時(shí)候,ACTION_DOWN會(huì)執(zhí)行,然后我們看到這么一行代碼:
handled |= mListener.onDown(ev);
mListener是我們傳遞的SimpleOnGestureListener,于是就看到了控制臺(tái)的第一個(gè)log:
03-02 21:51:29.706 17138-17138/com.leo.gestureimageview E/TAG: ====onDown=====
我們的onDown是打印了,然后handled |= mListener.onDown(ev);看一下我們返回的是什么值:
@Override public boolean onDown(MotionEvent e) { Log.e("TAG", "====onDown====="); return super.onDown(e); }
我們直接返回了super.onDown(e),接著我們看一下父類(lèi)返回的是什么:
public boolean onDown(MotionEvent e) { return false; }
可以看到,父類(lèi)直接返回了false,所以handled此時(shí)為false,然后當(dāng)ACTION_DOWN執(zhí)行完畢后,就回到了我們的自定義view中的onTouchEvent方法中了:
@Override public boolean onTouchEvent(MotionEvent event) { return detector.onTouchEvent(event); }
此時(shí)我們的view中的onTouchEvent 方法返回的是false,到了這里懂事件傳遞機(jī)制的小伙伴都懂,當(dāng)我們的onTouchEvent返回了false的話(huà),后面的事件都將接收不到了,也就是說(shuō)只能執(zhí)行ACTION_DOWN,那么有些小伙伴可能又要說(shuō)了,那我把view的clickable或者longclickable設(shè)置成true,事件不就可以傳遞了么?
好的~! 我們?cè)囈辉嚕?/p>
<com.leo.gestureimageview.MatrixImageView android:clickable="true" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="matrix" />
運(yùn)行代碼,還是只打印了那三個(gè)方法,那這又是怎么回事呢? 還記得我們view的onTouchEvent方法么?我們是這么寫(xiě)的:
@Override public boolean onTouchEvent(MotionEvent event) { return detector.onTouchEvent(event); }
如果改成這樣再試試:
@Override public boolean onTouchEvent(MotionEvent event) { detector.onTouchEvent(event); return super.onTouchEvent(event); }
拖動(dòng)手指返回結(jié)果:
好啦~??! 終于看到我們久違的結(jié)果了,如果我們還是想用以前的寫(xiě)法,把onTouchEvent的返回結(jié)果交給GestureDetector處理該怎么做呢?
@Override public boolean onTouchEvent(MotionEvent event) { return detector.onTouchEvent(event); }
我們只需要在回調(diào)方法的onDown中返回true即可:
@Override public boolean onDown(MotionEvent e) { Log.e("TAG", "====onDown====="); return true; }
我們?cè)俅芜\(yùn)行代碼并拖動(dòng)手指:
好啦~! 說(shuō)了那么多不知道小伙伴們理解了沒(méi)?還是不理解的小伙伴可以去看看我前幾篇事件傳遞的博客,嘻嘻~我們還是快點(diǎn)往下走吧….
我們長(zhǎng)按一下屏幕然后提起手指:
03-02 22:29:37.361 22104-22104/com.leo.gestureimageview E/TAG: ====onDown=====
03-02 22:29:37.367 22104-22104/com.leo.gestureimageview E/TAG: ====onSingleTapUp=====
03-02 22:29:37.663 22104-22104/com.leo.gestureimageview E/TAG: ====onSingleTapConfirmed=====
執(zhí)行了onDown=>onSingleTapUp=>onSingleTapConfirmed.
我們快速點(diǎn)擊一下屏幕:
03-02 22:31:48.603 22104-22104/com.leo.gestureimageview E/TAG: ====onDown=====
03-02 22:31:48.610 22104-22104/com.leo.gestureimageview E/TAG: ====onSingleTapUp=====
03-02 22:31:48.903 22104-22104/com.leo.gestureimageview E/TAG: ====onSingleTapConfirmed=====
執(zhí)行了onDown=>onSingleTapUp=>onSingleTapConfirmed.
然后我們?cè)俅位瑒?dòng)手指:
03-02 22:34:41.820 22104-22104/com.leo.gestureimageview E/TAG: ====onDown=====
03-02 22:34:41.920 22104-22104/com.leo.gestureimageview E/TAG: ====onShowPress=====
03-02 22:34:42.018 22104-22104/com.leo.gestureimageview E/TAG: ====onScroll=====
03-02 22:34:42.018 22104-22104/com.leo.gestureimageview E/TAG: distanceX===>-117.13138
03-02 22:34:42.018 22104-22104/com.leo.gestureimageview E/TAG: distanceY===>75.100464
03-02 22:34:42.036 22104-22104/com.leo.gestureimageview E/TAG: ====onScroll=====
03-02 22:34:42.036 22104-22104/com.leo.gestureimageview E/TAG: distanceX===>-75.859314
執(zhí)行順序:onDown=》onShowPress=》onScroll(很多次)
最后我們手指拖動(dòng)距離長(zhǎng)一點(diǎn)再快一點(diǎn):
03-02 22:47:42.453 5103-5103/com.leo.gestureimageview E/TAG: distanceX===>-274.69336
03-02 22:47:42.453 5103-5103/com.leo.gestureimageview E/TAG: distanceY===>-0.34838867
03-02 22:47:42.460 5103-5103/com.leo.gestureimageview E/TAG: ====onFling=====
03-02 22:47:42.460 5103-5103/com.leo.gestureimageview E/TAG: velocityX===>27284.943
03-02 22:47:42.460 5103-5103/com.leo.gestureimageview E/TAG: velocityY===>-95.6131
前 面還有一段log沒(méi)給出了,調(diào)用方法順序?yàn)椋簅nDown=》onShowPress=》onScroll(很多次)=》最后松開(kāi)手指的時(shí)候onFling();
好了~! 到這里,我們的回調(diào)方法中還有幾個(gè)沒(méi)有被調(diào)用,就是監(jiān)聽(tīng)雙擊事件的時(shí)候,于是我們雙擊屏幕:
03-02 22:50:34.786 5103-5103/com.leo.gestureimageview E/TAG: ====onDown=====
03-02 22:50:34.793 5103-5103/com.leo.gestureimageview E/TAG: ====onSingleTapUp=====
03-02 22:50:34.924 5103-5103/com.leo.gestureimageview E/TAG: ====onDoubleTap=====
03-02 22:50:34.924 5103-5103/com.leo.gestureimageview E/TAG: ====onDoubleTapEvent=====
03-02 22:50:34.924 5103-5103/com.leo.gestureimageview E/TAG: ====onDown=====
03-02 22:50:34.932 5103-5103/com.leo.gestureimageview E/TAG: ====onDoubleTapEvent=====
我們雙擊屏幕執(zhí)行的方法為:
onDown=>onSingleTapUp=>onDoubleTap=>onDoubleTapEvent=>onDoubleTapEvent
可見(jiàn),執(zhí)行了一次onDoubleTap,兩次onDoubleTapEvent
好啦~! 看完了SimpleOnGestureListener中所有方法的回調(diào),我們反過(guò)來(lái)再看一遍這些回調(diào)方法:
好啦~!說(shuō)了那么api內(nèi)容,下面寫(xiě)個(gè)小例子用一下GestureDetector:
package com.leo.gestureimageview; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Matrix; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; import android.view.GestureDetector; import android.view.MotionEvent; import android.widget.ImageView; public class MatrixImageView extends ImageView { private Matrix currMatrix; private GestureDetector detector; public MatrixImageView(Context context, AttributeSet attrs) { super(context, attrs); initView(); detector=new GestureDetector(context,onGestureListener); } private void initView() { currMatrix = new Matrix(); DisplayMetrics dm = getResources().getDisplayMetrics(); Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.test); bitmap = Bitmap.createScaledBitmap(bitmap, dm.widthPixels, dm.heightPixels, true); setImageBitmap(bitmap); } @Override public boolean onTouchEvent(MotionEvent event) { return detector.onTouchEvent(event); } private float currX; private float currY; private GestureDetector.SimpleOnGestureListener onGestureListener=new GestureDetector.SimpleOnGestureListener(){ @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { Log.e("TAG", "====onScroll====="); Log.e("TAG", "distanceX===>"+distanceX); Log.e("TAG", "distanceY===>"+distanceY); currX-=distanceX; currY-=distanceY; currMatrix.reset(); currMatrix.postTranslate(currX,currY); setImageMatrix(currMatrix); return super.onScroll(e1, e2, distanceX, distanceY); } }; }
代碼很短,想必大家都看得懂,就是一個(gè)隨著手指移動(dòng)而移動(dòng)的圖片:
好啦~~ 這篇有點(diǎn)長(zhǎng),為什么花這么久去研究GestureDetector,這也是為了給下一節(jié)的MoveGestureDetector、RotateGestureDetector、ShoveGestureDetector以及PhotoView這些大牛寫(xiě)的框架做鋪墊。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android中ImageView.src設(shè)置圖片拉伸、填滿(mǎn)控件的方法
- Android自定義圓角ImageView控件
- Android ImageView 不顯示JPEG圖片的問(wèn)題解決
- Android 自定義imageview實(shí)現(xiàn)圖片縮放實(shí)例詳解
- Android中ImageView實(shí)現(xiàn)選擇本地圖片并顯示功能
- Android自定義控件之圓形、圓角ImageView
- Android ImageView實(shí)現(xiàn)圖片裁剪和顯示功能
- Android實(shí)現(xiàn)ImageView陰影和圖層效果
- Android ImageView的selector效果實(shí)例詳解
相關(guān)文章
用Android Studio3.0新功能加快構(gòu)建速度
本文主要介紹了使用Android Studio3.0新功能,加快Android Studio的構(gòu)建速度等相關(guān)做法。2017-11-11Android音頻處理之通過(guò)AudioRecord去保存PCM文件進(jìn)行錄制,播放,停止,刪除功能
這篇文章主要介紹了Android音頻處理之通過(guò)AudioRecord去保存PCM文件進(jìn)行錄制,播放,停止,刪除功能的相關(guān)資料,需要的朋友可以參考下2016-11-11Android應(yīng)用創(chuàng)建桌面快捷方式代碼
這篇文章主要為大家詳細(xì)介紹了Android應(yīng)用創(chuàng)建桌面快捷方式代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09c++ mk文件出錯(cuò)Jni調(diào)用產(chǎn)生java.lang.UnsatisfiedLinkError錯(cuò)誤解決方法
錯(cuò)誤產(chǎn)生在我把方法從c語(yǔ)言轉(zhuǎn)為c++語(yǔ)言后產(chǎn)生的,后來(lái)檢查到這種錯(cuò)誤是因?yàn)閙k文件出錯(cuò),加載c文件和加載c++的文件所用的代碼不一樣,下面請(qǐng)看2013-11-11Android自定義View實(shí)現(xiàn)QQ消息氣泡
這篇文章主要為大家詳細(xì)介紹了Android自定義View實(shí)現(xiàn)QQ消息氣泡,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08利用Android實(shí)現(xiàn)光影流動(dòng)特效的方法詳解
Flutter 的畫(huà)筆類(lèi) Paint 提供了很多圖形繪制的配置屬性,來(lái)供我們繪制更豐富多彩的圖形。本篇我們引入一個(gè) Paint 類(lèi)新的屬性:maskFilter,再結(jié)合之前的 shader 和動(dòng)畫(huà),制作出光影流動(dòng)特效,感興趣的可以嘗試一下2022-07-07Android中的RecyclerView新組件初步上手指南
RecyclerView是Android L版本開(kāi)始采用的一個(gè)組件,被人們認(rèn)為用來(lái)代替?zhèn)鹘y(tǒng)的ListView,下面我們就一起來(lái)看一下Android中的RecyclerView新組件初步上手指南2016-06-06Kotlin類(lèi)型系統(tǒng)竟如此簡(jiǎn)單
這篇文章主要給大家介紹了關(guān)于Kotlin類(lèi)型系統(tǒng)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Kotlin具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09Kotlin?coroutineContext源碼層深入分析
表示一個(gè)元素或者是元素集合的接口。它有一個(gè)Key(索引)的Element實(shí)例集合,每一個(gè)Element的實(shí)例也是一個(gè)CoroutineContext,即集合中每個(gè)元素也是集合2022-11-11Android實(shí)現(xiàn)過(guò)渡動(dòng)畫(huà)、引導(dǎo)頁(yè) Android判斷是否第一次啟動(dòng)App
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)過(guò)渡動(dòng)畫(huà)、引導(dǎo)頁(yè),以及Android判斷是否第一次啟動(dòng)App,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-12-12