Android HapticFeedback(震動反饋)介紹

轉載請註明出處:http://blog.csdn.net/harryweasley/article/details/52806516

本篇文章已授權微信公衆號 hongyangAndroid (鴻洋)獨家發佈

 click.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                v.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING
                        );
            }
        });

通過以上的代碼,點擊視圖後,就會產生振動,並且不需要震動權限,不需要震動權限,不需要震動權限.

下面將分析具體源碼來一探究竟。

Android中長按一個控件的時候,想以震動提示用戶,除了用Vibrate類來做,還可以用到(HapticFeedback)震動反饋實現。

本篇博客,我們就一起來熟悉一下Android震動反饋,首先我們打開手機上的振動模式開光,這裏我是以小米手機來做模擬的,位置在設置—>聲音和震動—>觸摸時震動,如下圖所示:
這裏寫圖片描述

震動強度,我選擇了較強,以讓震動更明顯。

系統觸發震動

下面從一個例子,來開始本篇博客,對一個button註冊長按監聽:

        Button click= (Button) findViewById(R.id.click);
        click.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {

                Toast.makeText(MainActivity.this,"長按點擊",Toast.LENGTH_SHORT).show();

                //觸發震動反饋
                return true;
                //return false;
            }
        });

當你長按此button,彈出一個toast,並且震動了,但是,返回false並不會觸發震動。
現在看源碼分析一下,這是爲何。

button實現setOnLongClickListener方法,在父類TextView的父類View中,

View.setOnLongClickListener源碼:

/**
     * Register a callback to be invoked when this view is clicked and held. If this view is not
     * long clickable, it becomes long clickable.
     *
     * @param l The callback that will run
     *
     * @see #setLongClickable(boolean)
     */
    public void setOnLongClickListener(@Nullable OnLongClickListener l) {
        if (!isLongClickable()) {
            setLongClickable(true);
        }
        getListenerInfo().mOnLongClickListener = l;
    }

我們要看mOnLongClickListener是在哪裏調用的接口onLongClick方法,最終在View的源碼中找到

View.performLongClick源碼:

/**
     * Call this view's OnLongClickListener, if it is defined. Invokes the context menu if the
     * OnLongClickListener did not consume the event.
     *
     * @return True if one of the above receivers consumed the event, false otherwise.
     */
    public boolean performLongClick() {
        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);

        boolean handled = false;
        ListenerInfo li = mListenerInfo;
        if (li != null && li.mOnLongClickListener != null) {
            handled = li.mOnLongClickListener.onLongClick(View.this);
        }
        if (!handled) {
            handled = showContextMenu();
        }
        if (handled) {
            performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
        }
        return handled;
    }

可以看到
第13行執行了onLongClick方法,並且將返回值給了變量handled,
在第18行,hangdled爲true,執行performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);該方法最終觸發了震動反饋。

這就是爲什麼,onLongClick返回true的時候,纔會有震動效果。

自定義觸發震動

上節提到,在performHapticFeedback觸發震動,觀察源碼得知,用戶可以自己通過代碼來觸發。

如下文所示,點擊也會觸發震動反饋了:

        click.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                v.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
                  
            }
        });

現在我們就去performHapticFeedback源碼看下,都執行了什麼,

View.performHapticFeedback源碼:

/**
     * BZZZTT!!1!
     *
     * <p>Provide haptic feedback to the user for this view.
     *
     * <p>The framework will provide haptic feedback for some built in actions,
     * such as long presses, but you may wish to provide feedback for your
     * own widget.
     *
     * <p>The feedback will only be performed if
     * {@link #isHapticFeedbackEnabled()} is true.
     *
     * @param feedbackConstant One of the constants defined in
     * {@link HapticFeedbackConstants}
     */
    public boolean performHapticFeedback(int feedbackConstant) {
        return performHapticFeedback(feedbackConstant, 0);
    }

這裏解釋三個知識點:

1.只有在isHapticFeedbackEnabled()爲true的情況下,纔會觸發震動。之後會解釋在爲false的情況下,爲何不會觸發震動。

在xml裏,可以通過android:hapticFeedbackEnabled="false|true"來進行設置

在java代碼裏,可以通過view.setHapticFeedbackEnabled(boolean)來設置,

不過默認是true哦。

2.HapticFeedbackConstants的常量值,我們要用到的有三個,一個是LONG_PRESS(長按),第二個是FLAG_IGNORE_VIEW_SETTING(不受view的設置影響,即不受isHapticFeedbackEnabled()的影響),第三個是FLAG_IGNORE_GLOBAL_SETTING(不受系統設置的影響,即不受是否開啓震動反饋的影響)

3.我們看到該方法最終是返回的performHapticFeedback(int feedbackConstant, int flags)這個方法,

View.performHapticFeedback(int feedbackConstant, int flags)源碼:

/**
     * BZZZTT!!1!
     *
     * <p>Like {@link #performHapticFeedback(int)}, with additional options.
     *
     * @param feedbackConstant One of the constants defined in
     * {@link HapticFeedbackConstants}
     * @param flags Additional flags as per {@link HapticFeedbackConstants}.
     */
    public boolean performHapticFeedback(int feedbackConstant, int flags) {
        if (mAttachInfo == null) {
            return false;
        }
        //noinspection SimplifiableIfStatement
        if ((flags & HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0
                && !isHapticFeedbackEnabled()) {
            return false;
        }
        return mAttachInfo.mRootCallbacks.performHapticFeedback(feedbackConstant,
                (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0);
    }

看第15行的if語句,當flags=0時,flags & HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING爲0,又isHapticFeedbackEnabled()爲false,整個條件爲真,所以會執行17行,直接return。這也是爲什麼performHapticFeedback(int feedbackConstant)方法一定要在isHapticFeedbackEnabled()爲ture的情況下才會觸發震動。
在這裏說一下,&是按位與,返回數值,&&邏輯與,返回布爾值。
第19-20行,就是觸發底層震動的代碼了,之後代碼不做分析。

HapticFeedbackConstants常量

接下來,看下HapticFeedbackConstants三個常量,還是之前的代碼,如下所示:

click.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                v.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS
                        );
            }
        });

在單擊後,會觸發震動,但是如果xml加上 android:hapticFeedbackEnabled="false"這句話,單擊則沒有震動效果了。如下所示:

<Button
        android:layout_width="wrap_content"
        android:id="@+id/click"
        android:layout_height="wrap_content"
        android:hapticFeedbackEnabled="false"
        android:text="make" />

如果這時,想讓其震動,可以用如下方法來做:

 click.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                v.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING
                        );
            }
        });

忽略view的屬性設置。

還記得本篇文章之前,說去設置裏打開觸摸時震動的開關嗎,其實,用戶不打開,照樣可以讓其震動,只需要用如下的方法:

 click.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                v.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING
                        );
            }
        });

忽略系統設置,哈哈,是不是很變態的方法,不過不建議這樣做,畢竟用戶禁止了觸摸反饋,我們就沒必要繼續挑戰用戶極限了。

最後,我還要說一點,就是以上的方法,不需要震動權限,不需要震動權限,不需要震動權限.重要的事情說三遍。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章