源碼學(xué)習(xí)記錄-從android.view.View開始

View是安卓一切視圖的基礎(chǔ),我覺得先從這個(gè)點(diǎn)開始學(xué)習(xí)坷襟,向下擴(kuò)展會(huì)讓我更容易理解生年。

//包
package android.view;
//類
android.view.View

1抱婉、 實(shí)現(xiàn)接口 Drawable.Callback 蒸绩, 用來創(chuàng)建動(dòng)畫繪制時(shí)铃肯,用來實(shí)現(xiàn)調(diào)度和動(dòng)畫修改操作的,分為以下三個(gè)接口:

//繪制自身
void invalidateDrawable(@NonNull Drawable who);
//計(jì)劃執(zhí)行下一次動(dòng)畫
void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when);
//取消執(zhí)行前面計(jì)劃
void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what);

這個(gè)接口是在 setBackground(Drawable background) 中注冊(cè)監(jiān)聽的惦界。其實(shí)現(xiàn)如下:

    public void setBackground(Drawable background) {
        setBackgroundDrawable(background);
    }

    @Deprecated
    public void setBackgroundDrawable(Drawable background) {
        ...
        boolean requestLayout = false;

        mBackgroundResource = 0;

        //如果已有背景沾歪,如果此View綁定到了Window上雾消,則先使其不可見。
        if (mBackground != null) {
            if (isAttachedToWindow()) {
                mBackground.setVisible(false, false);
            }
            //然后再清空回調(diào)監(jiān)聽
            mBackground.setCallback(null);
            //再清空原背景的所有繪制任務(wù)
            unscheduleDrawable(mBackground);
        }

        if (background != null) {
            ...
            //設(shè)置當(dāng)前背景的布局方向            
            background.setLayoutDirection(getLayoutDirection());
            //這里獲取背景的padding值并根據(jù)布局方向設(shè)置布局參數(shù)。
            if (background.getPadding(padding)) {
                resetResolvedPaddingInternal();
                switch (background.getLayoutDirection()) {
                    case LAYOUT_DIRECTION_RTL:
                        mUserPaddingLeftInitial = padding.right;
                        mUserPaddingRightInitial = padding.left;
                        internalSetPadding(padding.right, padding.top, padding.left, padding.bottom);
                        break;
                    case LAYOUT_DIRECTION_LTR:
                    default:
                        mUserPaddingLeftInitial = padding.left;
                        mUserPaddingRightInitial = padding.right;
                        internalSetPadding(padding.left, padding.top, padding.right, padding.bottom);
                }
                mLeftPaddingDefined = false;
                mRightPaddingDefined = false;
            }

            // 判斷當(dāng)前背景大小是否與上一次繪制的背景大小相等泉哈,不想等則標(biāo)記為要重新繪制旨巷。
            if (mBackground == null
                    || mBackground.getMinimumHeight() != background.getMinimumHeight()
                    || mBackground.getMinimumWidth() != background.getMinimumWidth()) {
                requestLayout = true;
            }

            //賦值
            mBackground = background;
            //判斷是否需要狀態(tài)更新
            if (background.isStateful()) {
                background.setState(getDrawableState());
            }
            //判斷是否已添加到窗口中
            if (isAttachedToWindow()) {
                //設(shè)置是否可見
                background.setVisible(getWindowVisibility() == VISIBLE && isShown(), false);
            }

            applyBackgroundTint();

            // 最后設(shè)置監(jiān)聽
            background.setCallback(this);

            if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) {
                mPrivateFlags &= ~PFLAG_SKIP_DRAW;
                requestLayout = true;
            }
        } else {
            //這里的分支是做移除背景操作
            mBackground = null;
            if ((mViewFlags & WILL_NOT_DRAW) != 0
                    && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) {
                mPrivateFlags |= PFLAG_SKIP_DRAW;
            }

           //這里會(huì)請(qǐng)求布局一次
            requestLayout = true;
        }

        //再次計(jì)算一次透明度
        computeOpaqueFlags();

        //是否需要重新布局
        if (requestLayout) {
            requestLayout();
        }

        //標(biāo)記背景大小發(fā)生改變
        mBackgroundSizeChanged = true;

        //繪制
        invalidate(true);
        invalidateOutline();
    }

2采呐、 實(shí)現(xiàn)接口 KeyEvent.Callback 斧吐, 實(shí)現(xiàn)所有按鍵監(jiān)聽回調(diào)仲器,接口如下:

boolean onKeyDown(int keyCode, KeyEvent event);
boolean onKeyLongPress(int keyCode, KeyEvent event);
boolean onKeyUp(int keyCode, KeyEvent event);
boolean onKeyMultiple(int keyCode, int count, KeyEvent event);

具體實(shí)現(xiàn)方式如下:

    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (KeyEvent.isConfirmKey(keyCode)) {//檢測(cè)
            if ((mViewFlags & ENABLED_MASK) == DISABLED) {//檢測(cè)是否標(biāo)記為禁用
                return true;
            }
//判斷是否可點(diǎn)擊,或可長(zhǎng)點(diǎn)擊
            if (((mViewFlags & CLICKABLE) == CLICKABLE
                    || (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)
                    && (event.getRepeatCount() == 0)) {
                // 計(jì)算出中心點(diǎn)
                final float x = getWidth() / 2f;
                final float y = getHeight() / 2f;
                setPressed(true, x, y);//按壓
                checkForLongClick(0, x, y);//檢測(cè)是否為長(zhǎng)點(diǎn)擊
                return true;
            }
        }
        return false;
    }
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        if (KeyEvent.isConfirmKey(keyCode)) {
            if ((mViewFlags & ENABLED_MASK) == DISABLED) {
                return true;
            }
            if ((mViewFlags & CLICKABLE) == CLICKABLE && isPressed()) {
                setPressed(false);//取消按壓狀態(tài)

                if (!mHasPerformedLongPress) {
                    // 如果有長(zhǎng)按乏冀,則將長(zhǎng)按回調(diào)移除
                    removeLongPressCallback();
                    return performClick();
                }
            }
        }
        return false;
    }

3蝶糯、 下面開始從View的構(gòu)造函數(shù)開始正是入手,部分源碼如下:


    public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        this(context);//處理context賦值等操作

        final TypedArray a = context.obtainStyledAttributes(
                attrs, com.android.internal.R.styleable.View, defStyleAttr, defStyleRes);
       
            ···
            //初始化XML參數(shù)
            ···

        a.recycle();

        // Needs to be called after mViewFlags is set
        if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) {
            recomputePadding();
        }

        if (x != 0 || y != 0) {//是否需要滾動(dòng)
            scrollTo(x, y);
        }

        if (transformSet) {//設(shè)置一些偏移辆沦,旋轉(zhuǎn)放大縮小等參數(shù)
            setTranslationX(tx);
            setTranslationY(ty);
            setTranslationZ(tz);
            setElevation(elevation);
            setRotation(rotation);
            setRotationX(rotationX);
            setRotationY(rotationY);
            setScaleX(sx);
            setScaleY(sy);
        }

        if (!setScrollContainer && (viewFlagValues&SCROLLBARS_VERTICAL) != 0) {
            setScrollContainer(true);//設(shè)置內(nèi)容是否可以滾動(dòng)
        }
    }

以下 performClick() 用來實(shí)現(xiàn)OnClickListener操作昼捍,并作出一系列關(guān)聯(lián)操作:

public boolean performClick() {
        final boolean result;
        final ListenerInfo li = mListenerInfo;
        if (li != null && li.mOnClickListener != null) {//如果設(shè)置了監(jiān)聽,則播放聲音肢扯,并實(shí)現(xiàn)
            playSoundEffect(SoundEffectConstants.CLICK);
            li.mOnClickListener.onClick(this);
            result = true;
        } else {
            result = false;
        }
        //發(fā)送事件類型狀態(tài)
        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
        return result;
    }

callOnClick() 只調(diào)用實(shí)現(xiàn)監(jiān)聽,并不做一系列相關(guān)操作:

    public boolean callOnClick() {
        ListenerInfo li = mListenerInfo;
        if (li != null && li.mOnClickListener != null) {
            li.mOnClickListener.onClick(this);
            return true;
        }
        return false;
    }

4蔚晨、 這里有個(gè)厲害的了 onTouchEvent(MotionEvent event) 乍钻,處理觸摸事件,通常自定義View都會(huì)重寫它,這里來按下源碼银择。

    public boolean onTouchEvent(MotionEvent event) {
        final float x = event.getX();
        final float y = event.getY();
        final int viewFlags = mViewFlags;
        final int action = event.getAction();

        if ((viewFlags & ENABLED_MASK) == DISABLED) {
            if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) {
                setPressed(false);
            }
         
            return (((viewFlags & CLICKABLE) == CLICKABLE
                    || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)
                    || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE);
        }
        if (mTouchDelegate != null) {//代理分發(fā)
            if (mTouchDelegate.onTouchEvent(event)) {
                return true;
            }
        }
        //判斷是否可用點(diǎn)擊多糠、長(zhǎng)按、還是上下文點(diǎn)擊
        if (((viewFlags & CLICKABLE) == CLICKABLE ||
                (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) ||
                (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) {
            switch (action) {
                case MotionEvent.ACTION_UP:
                  boolean focusTaken = false;//焦點(diǎn)獲取
                        if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {
                            focusTaken = requestFocus();
                        }

                    ···
                         if (!post(mPerformClick)) {//分發(fā)點(diǎn)擊事件
                                 performClick();
                         }

                    ...
                    break;

                case MotionEvent.ACTION_DOWN:
                    if (isInScrollingContainer) {//這里會(huì)先判斷是否為內(nèi)部滾動(dòng)事件
                        ...
                    } else {
                        // 如果不是則欢摄,直接反饋按壓狀態(tài)熬丧,并檢測(cè)是否為長(zhǎng)按操作
                        setPressed(true, x, y);
                        checkForLongClick(0, x, y);
                    }
                    break;

                case MotionEvent.ACTION_CANCEL:
                    setPressed(false);//解除按壓狀態(tài)
                    removeTapCallback();移除回調(diào)
                    removeLongPressCallback();移除長(zhǎng)按回調(diào)
                    //重置狀態(tài)
                    mInContextButtonPress = false;
                    mHasPerformedLongPress = false;
                    mIgnoreNextUpEvent = false;
                    break;

                case MotionEvent.ACTION_MOVE:
               // Be lenient about moving outside of buttons
//這里有個(gè)mTouchSlop,是通過ViewConfiguration.get(context).getScaledTouchSlop();得到的怀挠。
                    if (!pointInView(x, y, mTouchSlop)) {
                        // Outside button
                        removeTapCallback();
                        if ((mPrivateFlags & PFLAG_PRESSED) != 0) {
                            // Remove any future long press/tap checks
                            removeLongPressCallback();

                            setPressed(false);
                        }
                    }
                    break;
            }

            return true;
        }

        return false;
    }

5析蝴、 其實(shí)我覺得最牛的方法應(yīng)該是 void setFlags(int flags, int mask) 雖然他是包類方法,但是這個(gè)方法的作用太強(qiáng)大了绿淋,所有的標(biāo)志位設(shè)置闷畸,幾乎都經(jīng)過它, flags 表示應(yīng)該設(shè)置的值吞滞,mask 表示改變的值的范圍佑菩,源碼部分分析如下:

    void setFlags(int flags, int mask) {
        final boolean accessibilityEnabled =
                AccessibilityManager.getInstance(mContext).isEnabled();
        final boolean oldIncludeForAccessibility = accessibilityEnabled && includeForAccessibility();

        int old = mViewFlags;//先臨時(shí)保存一份舊的
        mViewFlags = (mViewFlags & ~mask) | (flags & mask);

        int changed = mViewFlags ^ old;//判斷舊的和新的是否發(fā)生改變
        if (changed == 0) {
            return;//如果沒有改變則返回
        }
        int privateFlags = mPrivateFlags;

        /* Check if the FOCUSABLE bit has changed */
        if (((changed & FOCUSABLE_MASK) != 0) &&
                ((privateFlags & PFLAG_HAS_BOUNDS) !=0)) {//判斷是否改變了焦點(diǎn)
           ...
        }

        final int newVisibility = flags & VISIBILITY_MASK;
        if (newVisibility == VISIBLE) {//是否為VISIBLE
            if ((changed & VISIBILITY_MASK) != 0) {
                //是否發(fā)生改變
                mPrivateFlags |= PFLAG_DRAWN;
                invalidate(true);//重新繪制
                ...
            }
        }

        /* Check if the GONE bit has changed */
        if ((changed & GONE) != 0) {
            needGlobalAttributesUpdate(false);
            requestLayout();

            ...
        }

        /* Check if the VISIBLE bit has changed */
        if ((changed & INVISIBLE) != 0) {
            needGlobalAttributesUpdate(false);
            ...
        }

        if ((changed & VISIBILITY_MASK) != 0) {
            // If the view is invisible, cleanup its display list to free up resources
            if (newVisibility != VISIBLE && mAttachInfo != null) {
                cleanupDraw();
            }

            if (mParent instanceof ViewGroup) {
                ((ViewGroup) mParent).onChildVisibilityChanged(this,
                        (changed & VISIBILITY_MASK), newVisibility);
                ((View) mParent).invalidate(true);
            } else if (mParent != null) {
                mParent.invalidateChild(this, null);
            }
            ...
        }

        //后面是針對(duì)其它標(biāo)記位進(jìn)行判斷

        if ((changed & WILL_NOT_CACHE_DRAWING) != 0) {
            destroyDrawingCache();
        }

        if ((changed & DRAWING_CACHE_ENABLED) != 0) {
            destroyDrawingCache();
            mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
            invalidateParentCaches();
        }

        if ((changed & DRAWING_CACHE_QUALITY_MASK) != 0) {
            destroyDrawingCache();
            mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
        }

        if ((changed & DRAW_MASK) != 0) {
            if ((mViewFlags & WILL_NOT_DRAW) != 0) {
                if (mBackground != null
                        || (mForegroundInfo != null && mForegroundInfo.mDrawable != null)) {
                    mPrivateFlags &= ~PFLAG_SKIP_DRAW;
                } else {
                    mPrivateFlags |= PFLAG_SKIP_DRAW;
                }
            } else {
                mPrivateFlags &= ~PFLAG_SKIP_DRAW;
            }
            requestLayout();
            invalidate(true);
        }

        if ((changed & KEEP_SCREEN_ON) != 0) {
            if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) {
                mParent.recomputeViewAttributes(this);
            }
        }

        if (accessibilityEnabled) {
            ...
            //通知
        }
    }

6渠概、 bringToFront() 將視圖置頂诗眨,這個(gè)方法有時(shí)也很常用忧换,我們來看下它的內(nèi)部魄衅,調(diào)用父類方法,如下:

    public void bringChildToFront(View child) {
        final int index = indexOfChild(child);//查詢孩子的腳標(biāo)
        if (index >= 0) {//判斷是否存在
            removeFromArray(index);//先移除拢肆,然后再添加進(jìn)來
            addInArray(child, mChildrenCount);
            child.mParent = this;
            requestLayout();//重新布局
            invalidate();//重新繪制
        }
    }

7嵌戈、 dispatchAttachedToWindow(AttachInfo info, int visibility) 這個(gè)方法應(yīng)該是當(dāng)View綁定上窗口時(shí)则披,系統(tǒng)自動(dòng)調(diào)用的一忱。部分分析如下:

    void dispatchAttachedToWindow(AttachInfo info, int visibility) {
        mAttachInfo = info;
        if (mOverlay != null) {
            mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility);
        }
        mWindowAttachCount++;記錄綁定次數(shù)

        ...

        // Transfer all pending runnables.
        if (mRunQueue != null) {對(duì)綁定前操作的所有任務(wù)隊(duì)列莲蜘,在這里進(jìn)行統(tǒng)一處理。
            mRunQueue.executeActions(info.mHandler);
            mRunQueue = null;
        }
        performCollectViewAttributes(mAttachInfo, visibility);
        onAttachedToWindow();//調(diào)用此方法帘营,View子類都可重寫此方法票渠。

        ListenerInfo li = mListenerInfo;
        final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners =
                li != null ? li.mOnAttachStateChangeListeners : null;
        if (listeners != null && listeners.size() > 0) {
            //通知監(jiān)聽
            for (OnAttachStateChangeListener listener : listeners) {
                listener.onViewAttachedToWindow(this);
            }
        }

        int vis = info.mWindowVisibility;
        if (vis != GONE) {
            onWindowVisibilityChanged(vis);
            if (isShown()) {
                // Calling onVisibilityAggregated directly here since the subtree will also
                // receive dispatchAttachedToWindow and this same call
                onVisibilityAggregated(vis == VISIBLE);
            }
        }

        // Send onVisibilityChanged directly instead of dispatchVisibilityChanged.
        // As all views in the subtree will already receive dispatchAttachedToWindow
        // traversing the subtree again here is not desired.
        onVisibilityChanged(this, visibility);

        if ((mPrivateFlags&PFLAG_DRAWABLE_STATE_DIRTY) != 0) {
            // If nobody has evaluated the drawable state yet, then do it now.
            refreshDrawableState();
        }
        needGlobalAttributesUpdate(false);
    }

8、 相對(duì)綁定芬迄,肯定會(huì)有個(gè)解綁 dispatchDetachedFromWindow() 问顷,如下:

    void dispatchDetachedFromWindow() {
        AttachInfo info = mAttachInfo;
        if (info != null) {
            int vis = info.mWindowVisibility;
            if (vis != GONE) {
                onWindowVisibilityChanged(GONE);
                if (isShown()) {
                    // Invoking onVisibilityAggregated directly here since the subtree
                    // will also receive detached from window
                    onVisibilityAggregated(false);
                }
            }
        }

        onDetachedFromWindow();//對(duì)外繼承使用
        onDetachedFromWindowInternal();//內(nèi)部調(diào)用

        ...

        //其它通知
    }

9、 實(shí)在是看不下去了禀梳,最后來討論下 getViewTreeObserver(), 這是一個(gè)注冊(cè)監(jiān)聽視圖樹的觀察者(observer)择诈,在視圖樹種全局事件改變時(shí)得到通知。這個(gè)全局事件不僅還包括整個(gè)樹的布局出皇,從繪畫過程開始,觸摸模式的改變等哗戈。

內(nèi)部接口

    interface  ViewTreeObserver.OnGlobalFocusChangeListener         
  //當(dāng)在一個(gè)視圖樹中的焦點(diǎn)狀態(tài)發(fā)生改變時(shí)郊艘,所要調(diào)用的回調(diào)函數(shù)的接口類
 
  interface  ViewTreeObserver.OnGlobalLayoutListener
  //當(dāng)在一個(gè)視圖樹中全局布局發(fā)生改變或者視圖樹中的某個(gè)視圖的可視狀態(tài)發(fā)生改變時(shí),所要調(diào)用的回調(diào)函數(shù)的接口類
 
  interface  ViewTreeObserver.OnPreDrawListener
  //當(dāng)一個(gè)視圖樹將要繪制時(shí),所要調(diào)用的回調(diào)函數(shù)的接口類
 
  interface  ViewTreeObserver.OnScrollChangedListener
  //當(dāng)一個(gè)視圖樹中的一些組件發(fā)生滾動(dòng)時(shí)纱注,所要調(diào)用的回調(diào)函數(shù)的接口類
 
  interface  ViewTreeObserver.OnTouchModeChangeListener
  //當(dāng)一個(gè)視圖樹的觸摸模式發(fā)生改變時(shí)畏浆,所要調(diào)用的回調(diào)函數(shù)的接口類

可使用的公共方法

/**注冊(cè)一個(gè)回調(diào)函數(shù),當(dāng)在一個(gè)視圖樹中的焦點(diǎn)狀態(tài)發(fā)生改變時(shí)調(diào)用這個(gè)回調(diào)函數(shù)狞贱。
  * 參數(shù) listener    將要被添加的回調(diào)函數(shù)
  *異常 IllegalStateException       如果isAlive() 返回false
  */
 public void addOnGlobalFocusChangeListener (ViewTreeObserver.OnGlobalFocusChangeListener listener)
     
 
 /**注冊(cè)一個(gè)回調(diào)函數(shù)刻获,當(dāng)在一個(gè)視圖樹中全局布局發(fā)生改變或者視圖樹中的某個(gè)視圖的可視狀態(tài)發(fā)生改變時(shí)調(diào)用這個(gè)回調(diào)函數(shù)。
  *參數(shù) listener    將要被添加的回調(diào)函數(shù)
  *異常 IllegalStateException       如果isAlive() 返回false
  */
 public void addOnGlobalLayoutListener (ViewTreeObserver.OnGlobalLayoutListener listener)
  
 
  
 /**注冊(cè)一個(gè)回調(diào)函數(shù)瞎嬉,當(dāng)一個(gè)視圖樹將要繪制時(shí)調(diào)用這個(gè)回調(diào)函數(shù)蝎毡。
  *參數(shù) listener    將要被添加的回調(diào)函數(shù)
  *異常 IllegalStateException       如果isAlive() 返回false
  */
 public void addOnPreDrawListener (ViewTreeObserver.OnPreDrawListener listener)
 
    
 /**注冊(cè)一個(gè)回調(diào)函數(shù),當(dāng)一個(gè)視圖發(fā)生滾動(dòng)時(shí)調(diào)用這個(gè)回調(diào)函數(shù)氧枣。
  *參數(shù) listener    將要被添加的回調(diào)函數(shù)
  *異常 IllegalStateException       如果isAlive() 返回false
  */
 public void addOnScrollChangedListener (ViewTreeObserver.OnScrollChangedListener listener)  
 
 
 /**注冊(cè)一個(gè)回調(diào)函數(shù)沐兵,當(dāng)一個(gè)觸摸模式發(fā)生改變時(shí)調(diào)用這個(gè)回調(diào)函數(shù)。
  *參數(shù) listener    將要被添加的回調(diào)函數(shù)
  *異常 IllegalStateException       如果isAlive() 返回false
  */
 public void addOnTouchModeChangeListener (ViewTreeObserver.OnTouchModeChangeListener listener)
 
  
 //當(dāng)整個(gè)布局發(fā)生改變時(shí)通知相應(yīng)的注冊(cè)監(jiān)聽器便监。如果你強(qiáng)制對(duì)視圖布局或者在一個(gè)沒有附加到一個(gè)窗口的視圖的層次結(jié)構(gòu)或者在GONE狀態(tài)下扎谎,它可以被手動(dòng)的調(diào)用
 public final void dispatchOnGlobalLayout ()
    
 /**當(dāng)一個(gè)視圖樹將要繪制時(shí)通知相應(yīng)的注冊(cè)監(jiān)聽器。如果這個(gè)監(jiān)聽器返回true烧董,則這個(gè)繪制將被取消并重新計(jì)劃毁靶。如果你強(qiáng)制對(duì)視圖布局或者在一個(gè)沒有附加到一個(gè)窗口的視圖的層次結(jié)構(gòu)或者在一個(gè)GONE狀態(tài)下,它可以被手動(dòng)的調(diào)用
  *返回值  當(dāng)前繪制能夠取消并重新計(jì)劃則返回true逊移,否則返回false预吆。
  */
 public final boolean dispatchOnPreDraw ()
 
 /**指示當(dāng)前的ViewTreeObserver是否可用(alive)。當(dāng)observer不可用時(shí)螟左,任何方法的調(diào)用(除了這個(gè)方法)都將拋出一個(gè)異常啡浊。如果一個(gè)應(yīng)用程序保持和ViewTreeObserver一個(gè)歷時(shí)較長(zhǎng)的引用,它應(yīng)該總是需要在調(diào)用別的方法之前去檢測(cè)這個(gè)方法的返回值胶背。
  *返回值 但這個(gè)對(duì)象可用則返回true巷嚣,否則返回false   
  */
 public boolean isAlive ()
    
     
 /**移除之前已經(jīng)注冊(cè)的全局布局回調(diào)函數(shù)。
  *參數(shù) victim 將要被移除的回調(diào)函數(shù)
  *異常 IllegalStateException       如果isAlive() 返回false   
  */
 public void removeGlobalOnLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim)
  
 /**移除之前已經(jīng)注冊(cè)的焦點(diǎn)改變回調(diào)函數(shù)钳吟。
  *參數(shù) victim 將要被移除的回調(diào)函數(shù)
  *異常 IllegalStateException       如果isAlive() 返回false 
  */
 public void removeOnGlobalFocusChangeListener (ViewTreeObserver.OnGlobalFocusChangeListener victim)
  
 /**移除之前已經(jīng)注冊(cè)的預(yù)繪制回調(diào)函數(shù)廷粒。
  *參數(shù) victim 將要被移除的回調(diào)函數(shù)
  *異常 IllegalStateException       如果isAlive() 返回false  
  */
 public void removeOnPreDrawListener (ViewTreeObserver.OnPreDrawListener victim)
  
 /**移除之前已經(jīng)注冊(cè)的滾動(dòng)改變回調(diào)函數(shù)。
  *參數(shù) victim 將要被移除的回調(diào)函數(shù)
  *異常 IllegalStateException       如果isAlive() 返回false 
  */
 public void removeOnScrollChangedListener (ViewTreeObserver.OnScrollChangedListener victim)
 
 /**移除之前已經(jīng)注冊(cè)的觸摸模式改變回調(diào)函數(shù)
  *參數(shù) victim 將要被移除的回調(diào)函數(shù)
  *異常  IllegalStateException       如果isAlive() 返回false
  */
 public void removeOnTouchModeChangeListener (ViewTreeObserver.OnTouchModeChangeListener victim)

作者:Zyao89红且;轉(zhuǎn)載請(qǐng)保留此行坝茎,謝謝;

個(gè)人博客:http://zyao89.me

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末暇番,一起剝皮案震驚了整個(gè)濱河市嗤放,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌壁酬,老刑警劉巖次酌,帶你破解...
    沈念sama閱讀 222,183評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件恨课,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡岳服,警方通過查閱死者的電腦和手機(jī)剂公,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吊宋,“玉大人纲辽,你說我怎么就攤上這事×眩” “怎么了拖吼?”我有些...
    開封第一講書人閱讀 168,766評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)腺劣。 經(jīng)常有香客問我绿贞,道長(zhǎng),這世上最難降的妖魔是什么橘原? 我笑而不...
    開封第一講書人閱讀 59,854評(píng)論 1 299
  • 正文 為了忘掉前任籍铁,我火速辦了婚禮,結(jié)果婚禮上趾断,老公的妹妹穿的比我還像新娘拒名。我一直安慰自己,他們只是感情好芋酌,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評(píng)論 6 398
  • 文/花漫 我一把揭開白布增显。 她就那樣靜靜地躺著,像睡著了一般脐帝。 火紅的嫁衣襯著肌膚如雪同云。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,457評(píng)論 1 311
  • 那天堵腹,我揣著相機(jī)與錄音炸站,去河邊找鬼。 笑死疚顷,一個(gè)胖子當(dāng)著我的面吹牛旱易,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播腿堤,決...
    沈念sama閱讀 40,999評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼阀坏,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了笆檀?” 一聲冷哼從身側(cè)響起忌堂,我...
    開封第一講書人閱讀 39,914評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎酗洒,沒想到半個(gè)月后士修,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體妄迁,經(jīng)...
    沈念sama閱讀 46,465評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評(píng)論 3 342
  • 正文 我和宋清朗相戀三年李命,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片箫老。...
    茶點(diǎn)故事閱讀 40,675評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡封字,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出耍鬓,到底是詐尸還是另有隱情阔籽,我是刑警寧澤,帶...
    沈念sama閱讀 36,354評(píng)論 5 351
  • 正文 年R本政府宣布牲蜀,位于F島的核電站笆制,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏涣达。R本人自食惡果不足惜在辆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望度苔。 院中可真熱鬧匆篓,春花似錦、人聲如沸寇窑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)甩骏。三九已至窗市,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間饮笛,已是汗流浹背咨察。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留缎浇,地道東北人扎拣。 一個(gè)月前我還...
    沈念sama閱讀 49,091評(píng)論 3 378
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像素跺,于是被迫代替她去往敵國(guó)和親二蓝。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評(píng)論 2 360

推薦閱讀更多精彩內(nèi)容