天天看点

【Android】android镜像翻转1.翻转动画2.重写控件3.SurfaceView翻转4.手势翻转5.更优雅的方案6.总结

android镜像翻转指的是将屏幕进行水平的翻转,达到所有内容显示都会反向的效果,就像是在镜子中看到的界面一样。这种应用的使用场景相对比较受限,主要用在一些需要使用android手机界面进行镜面投影的地方,比如说车载手机hud导航之类的。

镜像翻转的效果如下:

【Android】android镜像翻转1.翻转动画2.重写控件3.SurfaceView翻转4.手势翻转5.更优雅的方案6.总结
【Android】android镜像翻转1.翻转动画2.重写控件3.SurfaceView翻转4.手势翻转5.更优雅的方案6.总结

镜像水平翻转前后效果

在没办法对硬件进行直接翻转的时候,只能从代码进行着手。最先想到的方法是一种比较弱的实现方案,就是对界面进行截图,然后对截图进行翻转,再让其替换掉原先的界面,这种方法是可行的,但是会出现很严重的内存问题,因为图片很耗内存,而且不利于动态界面的实现,比如控件会变动位置,控件内容会变化的情况。这就需要其他更靠谱的方案。

下面提供三种解决方案,能够解决一部分镜像翻转问题。

第一种方法是使用android翻转动画进行实现。

该方法需要重写动画,实现翻转,并将该动画添加到布局中,之后只要将动画的时长设置到0就能忽略掉动画过程,从而直接获取到动画的最终效果。需要重写animate类,用 android.graphics.camera和 android.graphics.matrix可以比较容易地实现翻转效果,代码实现如下:

调用的方法如下:

这里的reverse_layout是一个relativelayout的布局,调用了该段代码之后能将layout和layout所承载的内容都进行翻转。思路是将layoutview从中心点进行180度的水平翻转,需要设置setfillafter为true来保持翻转后的最终状态。这里需要注意的是,这段代码不能直接放在oncreate里面调用,因为在oncreate的时候,layout的大小还没有被计算出来,如果想在oncreate里面使用可以这样:

可以为layoutview加一个布局的监听,监听到layoutview布局加载了之后,就能正常获取layoutview的大小了,也就能正常输出效果了。

对控件进行重写是另外一个实现的思路。假设承载界面的layout是relativelayout,则可以对整个relativelayout进行重写,重写的代码可以如下:

之后,在布局xml中将最外层的relativelayout替换成reverselayout就能对界面进行翻转。这样的翻转能够将layout里面所有的控件都进行翻转,如果需要翻转的仅仅只是一个textview的话,则可以单单对一个textview进行重写,这个时候,就不需要重写dispatchdraw方法,而应该重写ondraw方法,如下:

ondraw和dispatchdraw的区别是ondraw只对当前的view有效,而不会影响其所包含的subview,而dispatchdraw则会将翻转效果传递到所有的subview。

以上两种方法能实现大多数view的翻转,但是都对surfaceview没有效果,因为surfaceview是通过双缓冲机制进行绘制的,不会经过ondraw或是dispatchdraw方法,也就不能对我们所进行的操作进行响应了,对于自定义的surfaceview来说,可以对在lockcanvas中获取的canvas对象进行翻转处理。

下面给出surfaceview翻转实现的代码:

采用该方法之后,对surfaceview也能进行翻转了,效果如下:

【Android】android镜像翻转1.翻转动画2.重写控件3.SurfaceView翻转4.手势翻转5.更优雅的方案6.总结

实际上,该方法是借助了第二种方法的思路,直接对canvas进行预先的处理从而达到我们所需要的效果的,所以也可以作为第二种方法的扩展。

需要注意的是,以上这几种方法仅仅是实现了显示的翻转,手势操作的位置并没有发生翻转。所以使用以上翻转方式的话需要结合手势翻转的实现,其实现思路是重写外层的viewgroup的onintercepttouchevent方法,对下发的motionevent进行一次翻转操作,使得childview接收到的手势都是反过来的。实现代码如下 :

对于普通view(非surfaceview),还有一个更加优雅的实现方案,而且不需要重写onintercepttouchevent方法,只需要调用父布局的setscaley或者setscalex方法即可。

采用动画和重写控件的方案都能实现界面翻转的效果,而且性能方面都十分不错。

但是这两种方法都会存在以下一些问题:

1.仅仅翻转显示内容,不会翻转点击的坐标位置。也就是说,如果布局内最左边存在着一个按钮,则翻转后,按钮将会显示在界面最右边,但是想要点击按钮的话,还是在界面原先按钮所在的最左边进行点击才会得到响应。这里可以采取在父布局中对坐标进行重新定位的方法。

代码例子发布在github:

<a target="_blank" href="https://github.com/obobear/androidreverseview">androidreverseview</a>