2012-10 模板拼图简介

前言

拼图是目前在手机上广泛使用的一个应用。该应用将多张图片组合到一张图片之中,便于在网络上传播。

拼图界面

该图是选择四张图片时候的一个布局。整个布局是通过3个LinearLayout实现的。将两个LinearLayout(在下文中称为子LinearLayout)放入一个LinearLayout(下文中称为父LinearLayout)中。这样做原因是实现起来快捷。而且通过修改3个LinearLayout的orientation属性,子LinearLayout的weight属性,子LinearLayout中ImageView的weight属性即可实现样式变换。该三个LinearLayout在photogrid_module.xml中已经定义。

整个实现一览


类图说明
模板拼图,自由拼图公用类:
PhotoGridDisplay:整个屏幕(各种按键).
PhotogridPreview: 定义拼图类的方法

模板拼图相关类:
PhotoGridModule: 实现PhotogridPreview中定义的方法,生成模板拼图
PhotogridStyle:实现模板切换

模板拼图相关类:PhotogridPreview 类中定义的部分方法

public abstract class PhotogridPreview {...

   abstract public RelativeLayout init(PhotoGridDisplay context,
           DisplayMetrics dm); //初始化
   abstract public boolean save(); //保存
   abstract public String getFilePath(); //获得文件路径
   abstract public void recycle(); //回收内存资源
   abstract public void changeStyle(); //变换样式
   abstract public void onPauseListener(); //Activity onPasue
  abstract public boolean isNeedSave(); //是否有必要保存成图片

...}


PhotoGridModule除了实现这些抽象方法,将每张图片将使用的数据结构,封装到 class ImageInfo 中。

   class ImageInfo {
       LinearLayout linearLayout;  //所在的LinearLayout
       ImageView imageView;			//对应的ImageView
       Bitmap bitmap;				//对应的bitmap
       Rect rect;						//所在的位置区域
       Matrix matrix;				
       Matrix savedMatrix;
       float minScaleR;				//最小缩放比例
       ImageInfo(LinearLayout linearLayout, ImageView imageView,
               Bitmap bitmap, Rect rect, Matrix matrix, Matrix savedMatrix) {
           this.linearLayout = linearLayout;
           this.imageView = imageView;
           this.bitmap = bitmap;
           this.rect = rect;
           this.matrix = matrix;
           this.savedMatrix = savedMatrix;
       }
   }

初始化界面的过程

PhotoGridModule中关于init()的实现。获得父LinearLayout获得主界面中选中的图片的path.将图片decode成bitmap.生成ImageInfo

初始化ImageInfo 时,是按照两个子LinearLayout各获得一半imageView来区分的。由于最后生成的组合图片有边框,图片与图片间有间隔,边框和间隔则通过设置margin实现,该实现的方法是通过PhotogridStyle.setLinearImageViewMargin处理。

Init完成后,会将init()生成的view添加到PhotoGridDisplay。

待Layout完成时,对ImageInfo 中rect进行初始化,并设置图片最小缩放minZoom(),图片全部在窗口中allInWindow(),图片的中心在窗口中心centerInWindow().

minZoom()

根据ImgaView窗口的宽/图片的宽,ImgaView窗口的长/图片的长的比值,取大者,作为最小缩放比率。

Matrix API:
boolean postScale(float sx, float sy)
Postconcats the matrix with the specified scale.

allInWindow()

通过判断bitmap的top, left, right, bottom相对于ImgaView窗口的位置判断窗口中是否有留白。若有留白,进行修正。


Matrix API:
boolean mapRect(RectF rect)
Apply this matrix to the rectangle, and write the transformed rectangle back into it.

boolean postTranslate(float dx, float dy)
Postconcats the matrix with the specified translation.

centerInWindow()

设置图片的中心在窗口的中心。

Matrix API:
boolean mapRect(RectF rect)
Apply this matrix to the rectangle, and write the transformed rectangle back into it.

boolean postTranslate(float dx, float dy)
Postconcats the matrix with the specified translation.

单指行为

用户可以通过一个手指,移动图片在框中的位置,也可以拖动图片在不同的框间切换。


通过View.OnTouchListener实现。MotionEvent.ACTION_DOWN:记录event事件的位置;根据ImageInfo 中rect 属性,判断哪张图片被选中了。MotionEvent.ACTION_MOVE:通过向matrix.postTranslate传递当前move event的坐标信息同action down时记录的坐标信息的增量,实现移动。

MotionEvent.ACTION_UP:判断event事件是不是在另外一个ImageInfo的rect 属性中,如果是,则交换两个ImageView对应的图片的ImageInfo信息,实现图片的位置的切换。对交互后的图片做minZoom,allInWindow;如果没有交互,只做allInWindow。

双指行为

通过双指操作同一张图片,可以实现对一张图片的缩放。

MotionEvent.ACTION_POINTER_DOWN:另外一个手指按下,通过spacing()判断和第一个手指间的distance是否大于10,如果大于10,则认为将进行缩放操作。并通过函数midPoint()记录两指间的中点位置。

MotionEvent.ACTION_MOVE:将当前两指间距离同最初两指间的距离做比较,将比值传递给matrix.postScale,实现缩放。在缩放时,如果超过最大缩放率MAX_SCALE,则使用初始化时保留的matrix,试图片恢复到最初状态。

保存

public boolean save()

保存是根据预览图中图片的位置信息,映射到一个新生成的Canvas,实现对图片的保存。映射中有两个关系需要注意:预览图中,图片尺寸的大小映射到新生成的Canvas的尺寸变化各图片bitmap到ImageView时的缩放比率.

该函数可能有更好的实现方式。

样式切换

样式切换时通过手摇行为触发,这里简单实现了一个手摇行为识别。

private boolean checkShakeReversed(float x) .我们想象一下一个手摇行为:拿着手机的一只手突然向着一个方向做加速运动,然后往回,停住。在这个过程中,决定是否发生一个手摇行为的关键点是前两步:加速运动,突然往回。

该函数实现的思路是,只依据x轴上的加速度分量进行处理。如果在向一个方向运动的时候,有前后两个加速度值大于我们设定的参考值,则认定加速运动发生;如果发生前后两个加速度的绝对值相反,则认定往回发生。

需要注意的是,往回的过程之前,会有一个减速的过程,需要把这个过程忽略掉。

发布了27 篇原创文章 · 获赞 2 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/wlia/article/details/42235699