尊重原创作者,转载请注明出处:
http://blog.csdn.net/gemmem/article/details/9967295
ViewRootImpl是一个和系统相关的类,一般程序开发可能不需要使用它,但是有时候为了实现一些高级功能,我们可以考虑使用ViewRootImpl这个类。
举一个例子:
在一般程序开发过程中,如果想得到当前View的touch事件的坐标x,y,我们一般会借助onTouch等回调函数,因为这些函数里面会带有系统传上来的MotionEvent参数,但是有些情况下,我们是无法依赖这种onTouch函数的,比如下面这种情况。
我们想实现View的拖拽功能,希望ImageView随着手指移动而移动,android给程序员提供了drag and drop框架,我们可以直接使用android的drag and drop API来实现这个功能。
框架已经帮我们实现了drag shadow的移动和事件分发,只需要我们调用startDrag即可。
而drag shadow的UI需要我们自己定义,关键函数如下:
onProvideShadowMetrics()
The system calls this method immediately after you callstartDrag()
.
Use it to send to the system the dimensions and touch point of the drag shadow. The method has two arguments:
dimensions
APoint
object.
The drag shadow width goes inx
and
its height goes iny
.
touch_point
APoint
object.
The touch point is the location within the drag shadow that should be under the user's finger during the drag. Its X position goes inx
and
its Y position goes iny
这个函数有2个参数,都是Point类型。
第一个是用来指定drag shadow的宽和高, point.x表示宽,point.y表示高;
第二个Point参数是指定drag shadow的位置,这里解释一下API定义shadow位置的方法:point.x表示在拖到过程中shadow的左上角在水平方向上到手指触摸点的距离,point.y表示在拖动过程中shadow的左上角在竖直方向上到手指触摸点的距离。
考虑一个实际问题,我们的ImageView是有大小的,它的尺寸是不能忽略的,我们可以长按ImageView的正中心来拖拽它,也可能长按ImageView左上角、右上角或者下边缘等地方来发起拖拽行为,很明显,在这些情形下,我们的手指触摸点到ImageView的左上角距离是不一样的,但是,我们希望在拖拽的过程中drag shadow的左上角和手指触摸点保持这种距离,因为这样显得比较自然,那么在onProvideShadowMetrics里面,我们的touch_point参数就需要动态计算,而不能写死,所以,我们需要得到手指触摸点坐标和ImageView左上角坐标,ImageView的位置坐标非常容易获得(view.getLocationOnScreen),难点在于我们怎么得到手指触摸点坐标,这里ViewRootImpl就派上用场了,ViewRootImpl有
个函数getLastTouchPoint(),它可以获得手机屏幕上最近一次触摸行为的触摸点坐标,有了ImageView左上角坐标和手指触摸点坐标,我就可以计算出手指触摸点和ImageView左上角的相对位置。
那么如何获得ViewRootImpl实例,这个很关键,请看代码:
View root = getRootView(); //getRootView是View.java中的public函数
if (root == null)
return;
final ViewRootImpl viewRoot = (ViewRootImpl)root.getParent();
上面的代码即可获得ViewRootImpl实例。
下面是构建drag shadow UI的完整代码:
private class SwitchDragShadowBuilder extends View.DragShadowBuilder
{
public SwitchDragShadowBuilder(View v)
{
super(v);
}
@Override
public void onProvideShadowMetrics (Point size, Point touch)
{
int width;
int height;
width = getView().getWidth();
height = getView().getHeight();
size.set(width, height);
View root = getRootView();
if (root == null)
return;
final ViewRootImpl viewRoot = (ViewRootImpl)root.getParent();
Point lastPoint = new Point();
viewRoot.getLastTouchPoint(lastPoint); //获得触摸点的坐标,相对于屏幕左上角
int pos = new int[2];
mImage.getLocationOnScreen(pos); //获得ImageView的坐标,相对于屏幕左上角
mTouchOffsetX = lastPoint.x - pos[0];
mTouchOffsetY = lastPoint.y - pos[1] + DRAG_OFFSET; //y方向加一个DRAG_OFFSET,表示长按后,我们希望drag shadow往上跳一段距离
touch.set(mTouchOffsetX, mTouchOffsetY); //set position between drag shadow and finger touch point
}
@Override
public void onDrawShadow(Canvas canvas)
{
getView().draw(canvas);
}
}
ViewRootImpl这个类里面有很多高级的public API,大家可以自己去研究,上面的这个例子只是抛砖引玉,期待大家的更多发现。
分享到:
相关推荐
在Android开发中,`android.view.ViewRootImpl$CalledFromWrongThreadException` 是一个常见的异常,它通常发生在尝试在非UI线程(主线程)中修改用户界面元素时。这个异常表明,只有创建视图的原始线程(即主线程)...
这要从 Choreographer 这个类说起了,Choreographer 是 Android 系统中一个非常重要的组件,负责管理应用程序的绘制和动画。Choreographer 的 drawFrame 方法会调用到 ViewRootImpl 的 performTraversals 方法,而 ...
这几个类都是Android系统架构中的重要组件。Activity是Android应用程序的入口,Window是Android系统中的一种窗口对象,WindowManager是Android系统中的一种窗口管理器,View是Android系统中的视图对象,ViewRootImpl...
在Service中使用Log类记录关键步骤,可以帮助调试和理解代码执行流程。 总之,Service和Toast在Android开发中都有其独特的应用场景。理解它们的使用方法和注意事项,对于构建高效、稳定的应用至关重要。通过...
事件分发不是直接到Activity或View,而是通过ViewRootImpl这个特殊类进行。ViewRootImpl作为Activity与视图树之间的接口,它在Activity的启动和恢复过程中初始化。当InputDispatcherThread接收到事件后,会通过...
以下是针对Android中使用的一些设计模式的详细说明: 1. **职责链模式**:在Android的输入管理系统中,职责链模式用于处理输入事件。例如,ViewRootImpl类内部的几个阶段处理类(如EarlyPostImeInputStage、...
事件进入Android应用层后,会通过`WindowManager`服务的`ViewRootImpl`类进行分发。`ViewRootImpl`是连接应用程序和系统服务的关键组件,它负责将事件从系统层面传递到应用程序的视图树。在`ViewRootImpl`中,`...
mWindow是一个抽象类Window的实例,具体实现在PhoneWindow类中。PhoneWindow的setContentView()方法执行时,会进行一系列操作,包括初始化DecorView和安装布局。 DecorView是Activity的顶级视图,它通常包含一个...
- 使用`ViewRootImpl.java`中的`findViewByTouchPoint()`方法或自定义方案,根据触摸点获取最顶层的可触摸View。 3. **判断是英文单词**: - 获取到的文本可能包含多个单词,需要使用正则表达式检查每个单词是否...
在Android开发中,实现类似微信的截图功能是一项常见的需求,而“ClipPicture”项目正是一个实现了这一功能的优秀示例,其模仿微信截图的相似度高达99%。这个开源项目提供了一套完整的解决方案,帮助开发者了解并...
这个"免root实现截屏Android例子源码"就是针对这种需求提供的解决方案。 首先,我们需要理解Android系统的权限机制。在Android 6.0(API级别23)及以上版本,应用需要在运行时请求权限,包括读写存储权限(READ_...
总的来说,Android Input子系统的事件分发流程涉及了从硬件驱动到应用程序的多个层级,包括InputDispatcher、InputManagerService、InputChannel、ViewRootImpl以及View层次结构。理解这一流程对于优化用户交互和...
Android UI操作必须在主线程(UI线程)中执行,否则会抛出`android.view.ViewRootImpl$CalledFromWrongThreadException`异常。因此,在子线程中进行倒计时计算后,我们需要使用`Handler`或`runOnUiThread`来更新UI。...
`handle_message_obtainMessage`这个主题涉及到的是Android中的Handler机制,它允许开发者在不同线程之间传递消息,并在特定线程(通常是UI线程)中执行回调。下面我们将深入探讨这个知识点。 首先,`Handler`是...
在Android开发领域,面试是检验一个开发者技能的重要环节。针对"基于Android的联想Android开发工程师面试题",我们可以深入探讨一些关键知识点,这些知识点对于学习Android的同学和毕业生来说至关重要。以下是一些...
这个“在Android上创建一个PopupWindow”的主题将深入探讨如何使用PopupWindow类,以及在实际应用中的一些关键知识点。 首先,PopupWindow是android.widget 패키지中定义的一个类,它提供了弹出窗口的功能。创建一...
在实际优化过程中,SystraceTest这个示例项目可能包含了一些用于演示和学习的场景,开发者可以参考该项目,实践使用Systrace工具,理解其分析结果,并从中学习如何改进UI性能。 总之,Systrace是Android性能优化的...
ViewRootImpl是Android视图系统的入口,它负责将事件传递给DecorView,这是每个Activity的顶级View。DecorView进一步将事件分发给Activity设置的ContentView。在这个过程中,事件的分发遵循“自顶向下”的原则,即从...
- 不要在非UI线程中更新UI,这将抛出` android.view.ViewRootImpl$CalledFromWrongThreadException`异常。 8. **源码分析**: 对于进阶学习,了解`Handler`、`Looper`和`MessageQueue`的源码有助于深入理解它们的...