文章摘要:
1谍夭、ListView設(shè)定的長按監(jiān)聽黑滴,在長按時(shí)最終通過Vibrate.vibrate來實(shí)現(xiàn)震動(dòng)。如果不想要震動(dòng)效果紧索,在長按Listener中返回false袁辈,即可。
2珠漂、View中提供了調(diào)用觸摸反饋震動(dòng)的接口晚缩,用戶可以很方便的為View增加改功能。
3媳危、用戶可以在設(shè)置-聲音和震動(dòng)(通知)中關(guān)閉觸摸震動(dòng)荞彼,這樣子就不會(huì)存在震動(dòng)效果了待笑。觸摸振動(dòng)接口來自:System.HAPTIC_FEEDBACK_ENABLED。
一暮蹂、在app開發(fā)中,我們可以很方便的開發(fā)一個(gè)list列表應(yīng)用程序椎侠。如下:
代碼如下:MainActivity.java
public class MainActivity extends ListActivity {
public static final String[] TITLES =
{
"Henry IV (1)",
"Henry V",
"Henry VIII",
"Richard II",
"Richard III",
"Merchant of Venice",
"Othello",
"King Lear"
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setListAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, TITLES));
getListView().setOnItemLongClickListener(new OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> adapterView, View view,
int position, long id) {
if(position%2==0){
return true;
}
return false;
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
二、通過上面的程序源代碼我纪,我們燒錄到手機(jī)中,可以發(fā)現(xiàn)postion = 0浅悉、2、4等list條目在長按時(shí)术健,發(fā)生了振動(dòng),1荞估、3、5沒有勘伺,難道與OnItemLongClickListener的返回boolean狀態(tài)有關(guān)跪腹?
下面我們就來追尋這個(gè)問題的答案。
- 1飞醉、首先冲茸,設(shè)定Listener:
frameworks/base/core/java/android/widget/AdapterView.java
/**
* Register a callback to be invoked when an item in this AdapterView has
* been clicked and held
*
* @param listener The callback that will run
*/
public void setOnItemLongClickListener(OnItemLongClickListener listener) {
if (!isLongClickable()) {
setLongClickable(true);
}
mOnItemLongClickListener = listener;
}
- 2、其次:當(dāng)我們在ListView中長按時(shí):調(diào)用performLongPress處理長按事件。
frameworks/base/core/java/android/widget/AbsListView.java#onTouchEvent
@Override
public boolean onTouchEvent(MotionEvent ev) {
vtev.offsetLocation(0, mNestedYOffset);
switch (actionMasked) {
case MotionEvent.ACTION_DOWN: {
onTouchDown(ev);
break;
}
}
frameworks/base/core/java/android/widget/AbsListView.java#onTouchDown
private void onTouchDown(MotionEvent ev) {
if ((motionPosition >= 0) && getAdapter().isEnabled(motionPosition)) {
// User clicked on an actual view (and was not stopping a
// fling). It might be a click or a scroll. Assume it is a
// click until proven otherwise.
mTouchMode = TOUCH_MODE_DOWN;
// FIXME Debounce
if (mPendingCheckForTap == null) {
**mPendingCheckForTap = new CheckForTap();**
}
mPendingCheckForTap.x = ev.getX();
mPendingCheckForTap.y = ev.getY();
**postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());//100ms**
}
}
frameworks/base/core/java/android/widget/AbsListView.java#CheckForTap
private final class CheckForTap implements Runnable {
if (longClickable) {
if (mPendingCheckForLongPress == null) {
mPendingCheckForLongPress = new CheckForLongPress();
}
mPendingCheckForLongPress.rememberWindowAttachCount();
postDelayed(mPendingCheckForLongPress, l ongPressTimeout);
} else {
mTouchMode = TOUCH_MODE_DONE_WAITING;
}
}
frameworks/base/core/java/android/widget/AbsListView.java#CheckForLongPress
boolean handled = false;
if (sameWindow() && !mDataChanged) {
handled = performLongPress(child, longPressPosition, longPressId);
}
if (handled) {
mTouchMode = TOUCH_MODE_REST;
setPressed(false);
child.setPressed(false);
} else {
mTouchMode = TOUCH_MODE_DONE_WAITING;
}
frameworks/base/core/java/android/widget/AbsListView.java#performLongPress
boolean performLongPress(final View child,
final int longPressPosition, final long longPressId) {
boolean handled = false;
if (mOnItemLongClickListener != null) {
handled = mOnItemLongClickListener.onItemLongClick(AbsListView.this, child,
longPressPosition, longPressId);
}
if (!handled) {
mContextMenuInfo = createContextMenuInfo(child, longPressPosition, longPressId);
handled = super.showContextMenuForChild(AbsListView.this);
}
if (handled) {
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
}
}
總結(jié):當(dāng)長按時(shí)轴术,如果返回true难衰,則會(huì)回調(diào)用performHapticFeedback,該方法是View中的一個(gè)方法逗栽,會(huì)產(chǎn)生震動(dòng)效果盖袭。
- 3、performHapticFeedback的處理過程
從這個(gè)方法的注釋可以看出祭陷,此處是View為了方便使用苍凛,而提供的工具方法趣席。
/**
* 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);
}
frameworks/base/core/java/android/view/View.java#performHapticFeedback
方法中會(huì)調(diào)用isHapticFeedbackEnabled來檢測開關(guān)是否開啟兵志,開關(guān)位置在:設(shè)置--聲音和震動(dòng)(通知)--觸摸震動(dòng)(觸摸反饋)
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);
}
frameworks/base/core/java/android/view/ViewRootImpl.java#performHapticFeedback
public boolean performHapticFeedback(int effectId, boolean always) {
try {
return mWindowSession.performHapticFeedback(mWindow, effectId, always);
} catch (RemoteException e) {
return false;
}
}
frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java#performHapticFeedback
@Override
public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always) {
if (pattern.length == 1) {
// One-shot vibration
mVibrator.vibrate(owningUid, owningPackage, pattern[0], VIBRATION_ATTRIBUTES);
} else {
// Pattern vibration
mVibrator.vibrate(owningUid, owningPackage, pattern, -1, VIBRATION_ATTRIBUTES);
}
return true;
}
總結(jié):經(jīng)過重重過程,我們看到最后觸摸震動(dòng)(觸摸反饋)還是調(diào)用mVibrator.vibrate來實(shí)現(xiàn)宣肚。
三想罕、總結(jié):
1、ListView設(shè)定的長按監(jiān)聽霉涨,在長按時(shí)最終通過Vibrate.vibrate來實(shí)現(xiàn)震動(dòng)按价。如果不想要震動(dòng)效果,在長按Listener中返回false笙瑟,即可楼镐。
2、View中提供了調(diào)用觸摸反饋震動(dòng)的接口往枷,用戶可以很方便的為View增加改功能框产。
3、用戶可以在設(shè)置-聲音和震動(dòng)(通知)中關(guān)閉觸摸震動(dòng)错洁,這樣子就不會(huì)存在震動(dòng)效果了秉宿。