Android学习小Demo(5)结合Matrix跟Porperty Animatin 实现推拉门效果

大家新年好!

前面我们讲了矩阵在平面上的一些常用的变换,再前面我们讲了关于Android中属性动画的一些应用,不过这些变换都是发生在平面上的,是二维的,没有立体效果。立体效果的产生,是透视的效果,远处的东西看起来小,而近处的东西看起来大,大小的变化,再加上一些光影的处理,就形成了一种立体的感观,比如下面的立方体:


在Android中,实现3D的效果,可以通过OpenGL/ES,Camera,也可以通过Matrix的PolyToPoly来实现。OpenGL比较复杂麻烦,但是其实现的效果也最好,在游戏制作中利用的比较多,而Camera是Android中提供的一个包装好的类,模拟了一个观察点,通过改变这个观察点,从而实现纵深的变化,达到3d的效果。

我们前两篇文章都在讲Matrix,那么这一章我们也通过Matrix,再通过属性动画中ValueAnimator的应用, 来简单实现一个推拉门的效果吧。

下面是效果图:



这是一个很简单的推拉门效果,但是却是理解Matrix中SetPolyToPoly的一个很好的例子。

在当前的Activity上面,上面是一张图片,下面是一个按钮。当点击按钮的时候,图片的右上角和右下角会慢慢往后移动,从而形成一个推的效果。

下面我们结合代码来讲一下实现的思路。

1)在MainActivity中,创建一个ValueAnimator,设置一个从0 到 1变化的比例因子,叫rotateFactor,在变化的同时去更新PolyToPolyView。

PolyToPolyView是一个自定义的View。

        ValueAnimator valueAnimator = ValueAnimator.ofFloat(0f,1f);		
		valueAnimator.addUpdateListener(new AnimatorUpdateListener() {
			
			@Override
			public void onAnimationUpdate(ValueAnimator arg0) {
				float rotateFactor = (Float)arg0.getAnimatedValue();
				polyView.setRotateFactor(rotateFactor);
			}
		});
		...		
		btnRotate.setOnClickListener(new OnClickListener() {			
			@Override
			public void onClick(View v) {
				valueAnimator.start();				
			}
		});

2)创建自定义的View的时候,首先获得图片的宽高(即右上角和右下角的坐标),并初始化两个数组,一个是图片原点的几个角的坐标点,一个是图片在新的位置的坐标点。

	private void init(){
		bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.photo1);
		w = bitmap.getWidth();
		h = bitmap.getHeight();
		srcPoly = new float[POINTS_NUMBER];
		dstPoly = new float[POINTS_NUMBER];
		matrix = new Matrix();				
	}

3)根据每次传进来的rotateFactor,计算新的图片右上角,右下角所处的位置(右上角的位置要比原来的低,右下角的点要比原来的高,从而形成一种透视的效果),然后利用Matrix.setPolyToPoly方法来将原来的点映射上新的点上。

public void calculateMatrix(){
		shouldDraw = true;
		if(rotateFactor == 1){
			shouldDraw = false;
			return;
		}
		translateFactor = 1 - rotateFactor;
		float translateWidth = w  * translateFactor;//移动的距离 
		
		float translateWidthPerfoldsquare = translateWidth * translateWidth;
		float deepth = (float)Math.sqrt(w * w - translateWidthPerfoldsquare);//利用勾股定理算出移动时,深度的变化
		
		float scaleFactor = DEPTH_CONSTANT / (DEPTH_CONSTANT + deepth);//以这个深度来计算缩放的一个比例
		
		float scaleWidth = w * translateFactor;//在图片右边往后移动的时候,在平面看去,图片的宽也会慢慢缩小。
		float scaleHeight = h * scaleFactor;//高也是一样,离得越远,高度就会越小
		float topScalePoint = (h - scaleHeight) / 2.f;//求出新的右上角的点
		float bottomScalePoint = topScalePoint + scaleHeight;//求出新的右下角的点
						
		srcPoly[0] = 0;
		srcPoly[1] = 0;
		srcPoly[2] = 0;
		srcPoly[3] = h;
		srcPoly[4] = w;
		srcPoly[5] = 0;
		srcPoly[6] = w;
		srcPoly[7] = h;
		
		dstPoly[0] = 0;			//左上角跟左下角的点是不动的
		dstPoly[1] = 0;
		dstPoly[2] = dstPoly[0];
		dstPoly[3] = h;
		dstPoly[4] = scaleWidth;	//右上角跟右下角的点是会慢慢往后移动的
		dstPoly[5] = topScalePoint;
		dstPoly[6] = dstPoly[4];
		dstPoly[7] = bottomScalePoint;
		
		if(dstPoly[4] <= dstPoly[0]){
			shouldDraw = false;
			return;
		}
		
		matrix.reset();
		matrix.setPolyToPoly(srcPoly, 0, dstPoly, 0, POINTS_NUMBER / 2);//将原来的坐标映射到新的点上面
	}
在这里,我们看一下setPolyToPoly这个方法。

    /**
     * Set the matrix such that the specified src points would map to the
     * specified dst points. The "points" are represented as an array of floats,
     * order [x0, y0, x1, y1, ...], where each "point" is 2 float values.
     *
     * @param src   The array of src [x,y] pairs (points)
     * @param srcIndex Index of the first pair of src values
     * @param dst   The array of dst [x,y] pairs (points)
     * @param dstIndex Index of the first pair of dst values
     * @param pointCount The number of pairs/points to be used. Must be [0..4]
     * @return true if the matrix was set to the specified transformation
     */
    public boolean setPolyToPoly(float[] src, int srcIndex,
                                 float[] dst, int dstIndex,
                                 int pointCount) {
这里我们看到pointCount这个参数,最大必须是4,也就是说,matric支持的映射点数最多就是4个点,而src和dst里面则是我们定义的坐标点,以[x0,y0,x1,y1,...]的形式存在,每两位为一个点,而srcIndex和dstIndex,则是表明我们要从哪个点开始映射的。在ApiDemo中,有提供一个PolyToPoly的例子,大家有兴趣可以去看一下。
在这里,我们就会利用这个方法,将坐标点的变换放到一个Matrix中。

3)当Animator在进行的时候,rotateFactor也会一直变化,相对应的,图片右上角和右下角的位置会一直被重新计算并刷新,就形成了往后推的效果。

4)在Canvas中,要去应用上面计算好的matrix,这里是利用了canvas.concat的方法,这是一个先乘(也即右乘),也就是实现这个matrix的变换。

	public void onDraw(Canvas canvas){
		calculateMatrix();
		if(shouldDraw){
			canvas.concat(matrix);
			canvas.drawBitmap(bitmap, 0,0, null);
		}
	}
总的实现思路大概就是这样。方法总比问题多,像我们如果要形成3d效果,方法其实还是有各种各样的,我们可能多学习一点,从而对android的应用也多了解一点。

源代码请点击

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值