- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试编写一个类似启动器的应用程序,它可以将小部件添加到其屏幕。
我正在使用 Leonardo Fischer 的教程 (http://leonardofischer.com/hosting-android-widgets-my-appwidgethost-tutorial/),它很棒。
为了删除小部件,用户应该长按小部件,这就是我遇到麻烦的地方;一些小部件(例如 WhatsApp Messagelist、Evernote 列表)允许您滚动它们。出于某种原因,如果您滚动,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/ ,您需要在父容器(在我的例子中是 mainlayout
)中实现 onInterceptTouchEvent
以在事件到达子容器(widgets)之前拦截和处理事件以我为例)。
所以我搜索了以下代码并尝试适应我的需求:
@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);
}
}
当我点击一个小部件时,上面的代码确实拦截了触摸事件,但它的逻辑似乎旨在拦截(并直接用于进一步处理)对小部件的长按。我实际需要的是在父 View 中拦截长按。
诀窍似乎在于 if (performLongClick())
,据我所知,它向小部件触发了一个 LongClick 事件...
...所以我想我现在的问题是如何在父 View 中跟踪长按。
对于处理 Android UI 事件的冗长(看似基本的)问题,我深表歉意,但从我用谷歌搜索来看,这似乎是一个非常复杂的话题..
最佳答案
所以它完成了...!我不确定这是否是一个优雅的解决方案,但它确实有效。
onInterceptTouchEvent
允许父 View 在事件发送给最终发送者之前对其进行操作。请注意,如果您触摸实际 View ,它不会触发。所以如果你有一个带有一些“空白”和一些元素的布局,onInterceptTouchEvent
不会触发如果你触摸布局的“空白”(你需要布局的onTouchEvent
在这种情况下)。
因为我们基本上只能跟踪ACTION_UP
、ACTION_MOVE
和ACTION_DOWN
事件,所以我们需要计时持续时间ACTION_DOWN/ACTION_UP
事件对来决定这是否是长按,所以我所做的如下:
public class time_counter {
private long begin_time;
private long end_time;
public time_counter(long i, long f) {
this.begin_time = i;
this.end_time = f;
}
public long getDuration() {
return (this.end_time - this.begin_time);
}
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// Consume any touch events for ourselves after longpress is triggered
// Watch for longpress events at this level to make sure
// users can always pick up this widget
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: {
cnt = new time_counter(ev.getEventTime(), (long)0);
break;
}
case MotionEvent.ACTION_MOVE: {
if (cnt != null) {
cnt.end_time = ev.getEventTime();
}
break;
}
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (cnt != null) {
cnt.end_time = ev.getEventTime();
}
Log.i(TAG, "DURATION: " + cnt.getDuration());
if (cnt.getDuration() > ViewConfiguration.getLongPressTimeout()) {
Log.i(TAG, "it's a longpress: " + this.toString());
if (processClick) {
processClick = false;
this.doRemoveWidget();
}
cancelLongPress();
return true;
}
break;
}
// Otherwise continue letting touch events fall through to children
return false;
}
每当 Android 发送一个 ACTION_DOWN
事件时,代码就会开始使用一个简单的“时间计数器”对象来跟踪它的持续时间。计数器的结束时间戳在整个 ACTION_MOVE
事件中不断更新,当 Android 发送 ACTION_UP
或 ACTION_CANCEL
时,代码会检查最终持续时间。如果超过 ViewConfiguration.getLongPressTimeout()
(默认 = 500 毫秒),它会触发操作。
请注意,在我的例子中,我需要一个 bool 变量来防止触发多个事件,因为我想使用 LongClick 来删除一个小部件。几乎总是会发生的第二次意外触发会触发空指针异常,因为小部件已被删除。
我用几个小部件(大的、小的、可配置的、有和没有 ScrollView 等等)测试了它,我没有发现任何故障。
同样,不确定这是一个优雅的还是“Android 明智”的解决方案,但它解决了我的问题。
希望这对您有所帮助!
引用:如果您需要关于触摸事件的优秀文章,请查看http://balpha.de/2013/07/android-development-what-i-wish-i-had-known-earlier/ .它给了我正确的“心态”来解决我的问题。
关于android - 父 View 没有得到长按事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35279659/
我目前正在寻找一些关于 jQuery 的建议,因为我认为我做错了,即使我得到了我想要的结果。 我想在更改时将输入的值更改为最接近的具有 .milestone 类的输入的值。我想要更改的输入是保持输入,
我已经阅读有关绑定(bind)、调用、申请的文章近一周了,对我来说仍然很复杂。我想我写的这个 jsfiddle 需要它们。然而,我没能做到,因为我仍然很困惑。 我尽力写了一些我上周从遇到这个问题的开发
我有一个项目生成代码。生成时间真的很长,所以我把它分成了多个项目,每个项目产生了整体的 20%。原始 POM 成为“父 POM”,子项依赖于它,仅包含一个单独的 Artifact ID 和一两个更改的
我正在使用局部 View 来创建父 subview 。我最理想的是父 View 上的提交按钮,用于保存子值。 我有以下模型。 public class Course { public int
我刚刚开始学习Rust,并且在理解所有权如何在我的案例中遇到一些麻烦: use std::ops::IndexMut; // =====================================
我是 JavaScript 新手,想了解更多有关它实例化父/子对象的顺序的信息。更具体地说,我想从编译器/浏览器的 Angular 理解以下代码片段。 var parent = { child:
我正在测试 Azure IaaS,并遇到了一个非常基本的问题。我有一个父 VHD 和子 VHD,已使用 csupload 将其作为页面 blob 上传,并且门户中显示图像和磁盘。然后我尝试将 pare
我的应用程序会定期为我坚持使用的对象请求更新 Core Data到网络服务。然后我需要更新我在主要上下文中拥有的对象(默认情况下 AppDelegate 中提供的对象)。编辑对象的不是用户,所以我需要
texT text text text text text 如何直接获取来自.menu ? 里面的 child 不应该采取。
我一直需要影响与其他元素相关的元素,但我的方法有点业余! 即到 // matched item where script is called from LINK 我使用; $(thi
我有两个表: 父子“类别”: id name parent_id 1 Food NULL 2 Pizza 1 3 Pasta
Linux 上的 Python 2.7.6。 我正在使用从父级继承的测试类。父类保存了许多子类共有的许多字段,我需要调用父类的 setUp 方法来初始化这些字段。调用 ParentClass.setU
我有一个处理图像、相册和相册类别的数据库。 一个专辑可以有多个专辑(子专辑),并且只有 1 级深度。 一张专辑仅属于一个专辑类别。 在这里做了一些研究,我相信最合适的数据库模型是这个 album_ca
我有一个关键字表,其中每个关键字都分配有一个 ID,并且是唯一的。我有第二个表,将父关键字的 ID 链接到子关键字的 ID。一个关键字最多可以有大约 800 个 child 或根本没有。 child
我经常使用这个 CSS 选择器 parent>child。我的设计在 Mozilla 和 Opera 中看起来不错。 但在 IE 中,它很糟糕。我知道 > 在 IE 中无法识别,但在 IE 中有什么替
我一直在用一个父对象构建一个系统,它在其中创建各种子对象,每个子对象都需要一个主对象才能运行。现在,到目前为止,我一直在创建 shared_ptr和 Child* ,所以当 Parent 和 所有 C
我从以下两个类中收到序列化兼容性错误。只有父类CommericalCustomer 实现了序列化。当具有如下所示的父/子关系时,使用可序列化接口(interface)的正确方法是什么? public
我正在开发一个程序并学习父/子进程。目前我的子进程是 exit(variable); 在我的 main() 中我有: signal(SIGCHLD, chldHandler); 在我的 main()
考虑以下两个具体类: public class A { protected void foo() { System.out.println("A foo"); bar
所以,我正在尝试建立这样的父/子类关系: class ParentClass where C : ChildClass { public void AddChild(C child)
我是一名优秀的程序员,十分优秀!