扩展RelativeLayout的,并覆盖dispatchDraw()创建一个可缩放的ViewGroup [英] Extending RelativeLayout, and overriding dispatchDraw() to create a zoomable ViewGroup

查看:173
本文介绍了扩展RelativeLayout的,并覆盖dispatchDraw()创建一个可缩放的ViewGroup的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我见过几个人问怎么放大一个完整的ViewGroup(如RelativeLayout的)一气呵成。目前,这是我需要实现。最明显的方法,对我来说,将是保持缩放比例系数为地方单个变量;并在每个子查看'的OnDraw()方法,即比例因子将被施加到帆布被绘制的图形之前。

不过,在这之前,我曾尝试要聪明(HA - 通常是一个坏主意),并延长RelativeLayout的,进入一类称为ZoomableRelativeLayout。我的想法是,任何规模的转变可能只是一次应用到画布上覆盖dispatchDraw()函数,因此会有完全没有必要单独申请的放大任何子意见。

下面是我在我的ZoomableRelativeLayout一样。这只是一个简单的扩展RelativeLayout的,用dispatchDraw()被覆盖:

 保护无效dispatchDraw(帆布油画){
    canvas.save(Canvas.MATRIX_SAVE_FLAG);
    canvas.scale(mScaleFactor,mScaleFactor);
    super.dispatchDraw(画布);
    canvas.restore();
}
 

的mScaleFactor是通过在同一类中的ScaleListener操纵。

它的实际工作。我可以捏缩放ZoomableRelativeLayout,和所有的内所持的观点正确地重新调整了一起。

除了有一个问题。其中一些孩子的看法是动画,所以我定期调用无效()在他们身上。当比例为1,这些孩子的意见被视为重绘定期完美的罚款。当比例尺为1以外,那些动画子视图仅见于其可视面积的一部分来更新 - 或根本不 - 根据变焦比例。

我最初的想法是,当一个人子视图的无效()被调用,那么它可能被单独重绘的系统,而不是传递从父RelativeLayout的的dispatchDraw()一个画布,这意味着子视图结束清爽的本身没有应用的缩放比例。但奇怪的是,孩子的意见被重绘屏幕上的内容是正确的缩放比例。这是几乎一样,如果该系统决定的后盾位图实际更新该地区仍然未缩放 - 如果是有道理的。换一种方式,如果我有一个动画的子View和我已渐行渐放大,从1最初的规模,如果我们把一个虚构的箱子在哪里的孩子认为是该地区时,变焦倍数为1 ,然后调用无效()仅会导致该虚拟盒显卡的刷新。但是,这被视为图形更新的的正在做正确的规模。如果放大到目前为止,孩子观点现在搬到彻底远离它是一个比例为1,那么它的任何部分都被看作是刷新。我再举一个例子:想象我的孩子认为是一个球是由动画黄色和红色之间切换。如果我放大一点点,使球移动到右侧和下,在某一点上,你只会看到球的左上角季度动画的色彩。

如果我不断地放大和缩小,我看到孩子的意见正确的,完全动画。这是因为,整个的ViewGroup被重绘。

我希望这是有道理的;我试着解释作为最好的,我可以。我是一个有点失败者的我可缩放的ViewGroup策略?有另一种方式?

谢谢

崔佛

解决方案

如果你申请的比例因子给你的孩子的绘画,还需要相应的比例系数适用于所有其他的互动与他们 - 调度触摸事件,废止等。

所以除了dispatchDraw(),您将需要重写,并适当调整至少这些方法的行为。为了照顾无效的,你需要重写这个方法来调整孩子正确的坐标:

<一个href="http://developer.android.com/reference/android/view/ViewGroup.html#invalidateChildInParent%28int%5b%5d,%20android.graphics.Rect%29">http://developer.android.com/reference/android/view/ViewGroup.html#invalidateChildInParent(int[], android.graphics.Rect)

如果您希望用户能够与孩子进行交互视图中,您还需要重写此调整触摸坐标,他们被分派给孩子适当地之前:

<一个href="http://developer.android.com/reference/android/view/ViewGroup.html#dispatchTouchEvent(android.view.MotionEvent">http://developer.android.com/reference/android/view/ViewGroup.html#dispatchTouchEvent(android.view.MotionEvent)

此外,我会强烈建议你实现这一切里面一个简单的ViewGroup子类,具有单个子视图其管理的。这将摆脱任何行为RelativeLayout的推出在自己的ViewGroup的复杂性,简化了你所需要的处理和调试自己的code。把RelativeLayout的为您的特殊变焦的ViewGroup的孩子。

最后,人们改善你的code - 在dispatchDraw()要保存画布状态的的应用比例因子。这保证了孩子不能修改已设置的转变。<​​/ P>

I've seen a few people ask how to zoom an entire ViewGroup (such as a RelativeLayout) in one go. At the moment this is something I need to achieve. The most obvious approach, to me, would be to hold the zoom scale factor as a single variable somewhere; and in each of the child Views' onDraw() methods, that scale factor would be applied to the Canvas prior to graphics being drawn.

However, before doing that, I have tried to be clever (ha - usually a bad idea) and extend RelativeLayout, into a class called ZoomableRelativeLayout. My idea is that any scale transformation could be applied just once to the Canvas in the overridden dispatchDraw() function, so that there would be absolutely no need to separately apply the zoom in any of the child views.

Here's what I did in my ZoomableRelativeLayout. It's just a simple extension of RelativeLayout, with dispatchDraw() being overridden:

protected void dispatchDraw(Canvas canvas){         
    canvas.save(Canvas.MATRIX_SAVE_FLAG);       
    canvas.scale(mScaleFactor, mScaleFactor);
    super.dispatchDraw(canvas);     
    canvas.restore();       
}

The mScaleFactor is manipulated by a ScaleListener in the same class.

It does actually work. I can pinch to zoom the ZoomableRelativeLayout, and all of the views held within properly rescale together.

Except there's a problem. Some of those child views are animated, and hence I periodically call invalidate() on them. When the scale is 1, those child views are seen to redraw periodically perfectly fine. When the scale is other than 1, those animated child views are only seen to update in a portion of their viewing area - or not at all - depending on the zoom scale.

My initial thinking was that when an individual child view's invalidate() is being called, then it's possibly being redrawn individually by the system, rather than being passed a Canvas from the parent RelativeLayout's dispatchDraw(), meaning that the child view ends up refreshing itself without the zoom scale applied. But oddly, the elements of the child views that are redrawn on the screen are to the correct zoom scale. It's almost as if the area that the system decides to actually update in the backing bitmap remains unscaled - if that makes sense. To put it another way, if I have a single animated child View and I gradually zoom in further and further from an initial scale of 1, and if we place an imaginary box on the area where that child view is when the zoom scale is 1, then the calls to invalidate() only cause a refresh of the graphics in that imaginary box. But the graphics that are seen to update are being done to the right scale. If you zoom in so far that the child view has now moved completely away from where it was with a scale of 1, then no part of it at all is seen to refresh. I'll give another example: imagine my child view is a ball that animates by switching between yellow and red. If I zoom in a little bit such that the ball moves to the right and down, at a certain point you'll just see the top-left quarter of the ball animate colours.

If I continuously zoom in and out, I see the child views animate properly and entirely. This is because the entire ViewGroup is being redrawn.

I hope this makes sense; I've tried to explain as best as I can. Am I on a bit of a loser with my zoomable ViewGroup strategy? Is there another way?

Thanks,

Trev

解决方案

If you are applying a scale factor to the drawing of your children, you also need to apply the appropriate scale factor to all of the other interactions with them -- dispatching touch events, invalidates, etc.

So in addition to dispatchDraw(), you will need to override and appropriate adjust the behavior of at least these other methods. To take care of invalidates, you will need to override this method to adjust the child coordinates appropriately:

http://developer.android.com/reference/android/view/ViewGroup.html#invalidateChildInParent(int[], android.graphics.Rect)

If you want the user to be able to interact with the child views you will also need to override this to adjust touch coordinates appropriately before they are dispatched to the children:

http://developer.android.com/reference/android/view/ViewGroup.html#dispatchTouchEvent(android.view.MotionEvent)

Also I would strongly recommend you implement this all inside of a simple ViewGroup subclass that has a single child view it manages. This will get rid of any complexity of behavior that RelativeLayout is introducing in its own ViewGroup, simplifying what you need to deal with and debug in your own code. Put the RelativeLayout as a child of your special zooming ViewGroup.

Finally, one improvement to your code -- in dispatchDraw() you want to save the canvas state after applying the scaling factor. This ensures that the child can't modify the transformation you have set.

这篇关于扩展RelativeLayout的,并覆盖dispatchDraw()创建一个可缩放的ViewGroup的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆