您的位置:首页 > 移动开发 > Android开发

android中如何使用ViewRootImpl这个类

2015-08-10 09:39 423 查看

尊重原创作者,转载请注明出处:

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 call 
startDrag()
.
Use it to send to the system the dimensions and touch point of the drag shadow. The method has two arguments:
dimensionsA 
Point
 object.
The drag shadow width goes in 
x
 and
its height goes in 
y
.touch_pointA 
Point
 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 in 
x
 and
its Y position goes in 
y

这个函数有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实例,这个很关键,请看代码:

[java]
view plaincopyprint?

View root = getRootView(); //getRootView是View.java中的public函数
  
if (root == null)  
    return;  
  
final ViewRootImpl viewRoot = (ViewRootImpl)root.getParent();  

View root = getRootView(); //getRootView是View.java中的public函数
if (root == null)
return;

final ViewRootImpl viewRoot = (ViewRootImpl)root.getParent();


上面的代码即可获得ViewRootImpl实例。

下面是构建drag shadow UI的完整代码:

[java]
view plaincopyprint?

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);  
        }  
    }  

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,大家可以自己去研究,上面的这个例子只是抛砖引玉,期待大家的更多发现。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: