【发布时间】:2016-02-08 21:27:08
【问题描述】:
我正在尝试编写一个类似启动器的应用程序,可以将小部件添加到其屏幕。
我正在使用 Leonardo Fischer 的教程 (http://leonardofischer.com/hosting-android-widgets-my-appwidgethost-tutorial/),这很棒。
为了删除小部件,用户应该长按小部件,这就是我遇到麻烦的地方;一些小部件(例如 WhatsApp 消息列表、印象笔记列表)允许您滚动它们。出于某种原因,如果您滚动,Android 会触发一个 LongClick 事件,该事件会错误地删除小部件...
我的代码: (创建小部件并设置 LongClickListener)
public void createWidget(Intent data) {
Bundle extras = data.getExtras();
int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
final LauncherAppWidgetHostView hostView = (LauncherAppWidgetHostView) mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
hostView.setAppWidget(appWidgetId, appWidgetInfo);
// relative layout
//RelativeLayout.LayoutParams lp = new RelativeLayout()
//mainlayout.addView(hostView, lp);
mainlayout.addView(hostView);
// [COMMENTED OUT] hostView.setOnLongClickListener(new AppWidgetLongClickListener(hostView));
}
更新
无数小时后,我想我部分了解发生了什么,但我仍然无法获得正确的行为。
根据http://balpha.de/2013/07/android-development-what-i-wish-i-had-known-earlier/,您需要在父容器中实现onInterceptTouchEvent(在我的情况下为mainlayout)以在事件到达子容器(我的小部件案例)。
所以我搜索了以下代码并尝试适应我的需求:
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// Consume any touch events for ourselves after longpress is triggered
//Log.i(TAG,"OnIntercept: "+ev.toString());
if (mHasPerformedLongPress) {
Log.i(TAG,"Longpress OK!: "+ev.toString());
mHasPerformedLongPress = false;
return true;
}
// Watch for longpress events at this level to make sure
// users can always pick up this widget
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: {
postCheckForLongClick();
break;
}
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
mHasPerformedLongPress = false;
if (mPendingCheckForLongPress != null) {
removeCallbacks(mPendingCheckForLongPress);
}
break;
}
// Otherwise continue letting touch events fall through to children
return false;
}
class CheckForLongPress implements Runnable {
private int mOriginalWindowAttachCount;
public void run() {
Log.i(TAG,"Inside RUN");
if (getParent()!= null) {
Log.i(TAG,"getParent:"+getParent().toString());
}
if ((getParent() != null) && hasWindowFocus()
&& (mOriginalWindowAttachCount == getWindowAttachCount())
&& !mHasPerformedLongPress) {
if (performLongClick()) { // <-- DOESN'T WORK :(
mHasPerformedLongPress = true;
}
}
}
public void rememberWindowAttachCount() {
mOriginalWindowAttachCount = getWindowAttachCount();
}
}
private void postCheckForLongClick() {
mHasPerformedLongPress = false;
if (mPendingCheckForLongPress == null) {
mPendingCheckForLongPress = new CheckForLongPress();
}
mPendingCheckForLongPress.rememberWindowAttachCount();
postDelayed(mPendingCheckForLongPress, ViewConfiguration.getLongPressTimeout());
}
@Override
public void cancelLongPress() {
super.cancelLongPress();
mHasPerformedLongPress = false;
if (mPendingCheckForLongPress != null) {
removeCallbacks(mPendingCheckForLongPress);
}
}
当我单击小部件时,上面的代码确实拦截了触摸事件,但它的逻辑似乎旨在拦截(并直接用于进一步处理)对小部件的长按。我真正需要的是拦截父视图中的长按。
诀窍似乎在于 if (performLongClick()),据我所知,它会触发一个 LongClick 事件到小部件...
...所以我想我现在的问题是如何在父视图中跟踪长按。
对于关于处理 Android UI 事件的冗长(而且看似基本的)问题很抱歉,但从我在 Google 上搜索的内容来看,这似乎是一个非常复杂的话题..
【问题讨论】:
标签: android android-widget android-appwidget