转载请注明出处,谢谢:http://blog.csdn.net/harryweasley/article/details/46678315
提前声明:本篇博客是基于电视机顶盒的,全部操作是用遥控器。
先看下效果图
如上图所示,图片放大,并且在最前方,可以遮盖住后面的图片。
在做放大效果之前,我们先创建一个类ScaleAnimEffect。
package com.amt.appstore.activity;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.ScaleAnimation;
public class ScaleAnimEffect {
private long duration;
private float fromAlpha;
private float fromXScale;
private float fromYScale;
private float toAlpha;
private float toXScale;
private float toYScale;
public void setAttributs(float paramFloat1, float paramFloat2,
float paramFloat3, float paramFloat4, long paramLong) {
this.fromXScale = paramFloat1;
this.fromYScale = paramFloat3;
this.toXScale = paramFloat2;
this.toYScale = paramFloat4;
this.duration = paramLong;
}
public Animation createAnimation() {
/**
* @param fromX
* 动画开始前水平方向的伸缩比例大小
* @param toX
* 动画结束后,水平方向的伸缩比例大小
* @param fromY
* 动画开始前,竖直方向的比例大小
* @param toY
* 动画结束结束后,竖直方向的比例大小
* @param pivotXType
* 指定pivotXValue以哪个为坐标点为中心来旋转。 Animation.ABSOLUTE,
* Animation.RELATIVE_TO_SELF, 或者
* Animation.RELATIVE_TO_PARENT这三个其中之一。
* @param pivotXValue
* 正在伸缩的对象的点的x坐标,指定为绝对数,并且0是左边缘(当对象改变尺寸的时候,点保持不变。)
* 如果pivotXType是
* Animation.ABSOLUTE,这个值既可以是绝对数,也可以为百分数(1.0位100%)
*
* @param pivotYType
* 指定pivotYValue以哪个为坐标点为中心来旋转。 Animation.ABSOLUTE,
* Animation.RELATIVE_TO_SELF, 或者
* Animation.RELATIVE_TO_PARENT这三个其中之一。
* @param pivotYValue
* 正在伸缩的对象的点的y坐标,指定为绝对数,并且0是左边缘(当对象改变尺寸的时候,点保持不变。)
* 如果pivotYType是
* Animation.ABSOLUTE,这个值既可以是绝对数,也可以为百分数(1.0位100%)
*/
ScaleAnimation localScaleAnimation = new ScaleAnimation(
this.fromXScale, this.toXScale, this.fromYScale, this.toYScale,
Animation.RELATIVE_TO_SELF, 0.5F, Animation.RELATIVE_TO_SELF,
0.5F);
// 动画执行完成后,是否停留在执行完的状态
localScaleAnimation.setFillAfter(true);
// 在动画开始的地方速率比较慢,然后开始加速
localScaleAnimation.setInterpolator(new AccelerateInterpolator());
// 设置动画持续时间
localScaleAnimation.setDuration(this.duration);
return localScaleAnimation;
}
}
关于Interpolator,被用于修饰动画效果,定义动画的变化率。
AccelerateDecelerateInterpolator 在动画开始与结束的地方速率改变比较慢,在中间的时候加速
AccelerateInterpolator 在动画开始的地方速率改变比较慢,然后开始加速
AnticipateInterpolator 开始的时候向后然后向前甩
AnticipateOvershootInterpolator 开始的时候向后然后向前甩一定值后返回最后的值
BounceInterpolator 动画结束的时候弹起
CycleInterpolator 动画循环播放特定的次数,速率改变沿着正弦曲线
DecelerateInterpolator 在动画开始的地方快然后慢
LinearInterpolator 以常量速率改变
OvershootInterpolator 向前甩一定值后再回到原来位置
关于ScaleAnimation的构造函数后面四个参数,我是真的头大,经过看官方的翻译,还是有点云里雾里,就先这样定义吧。
接下来看xml布局文件activity_increase.xml。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="fill_parent"
>
<FrameLayout
android:id="@+id/flid1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:focusable="false" >
<ImageView
android:id="@+id/itvimageid1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:focusable="true"
android:focusableInTouchMode="true"
android:scaleType="fitXY"
android:src="@drawable/ic_empty" />
</FrameLayout>
<FrameLayout
android:id="@+id/flid2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="80dp"
android:layout_marginTop="10dp"
android:focusable="false" >
<ImageView
android:id="@+id/itvimageid2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:focusable="true"
android:focusableInTouchMode="true"
android:scaleType="fitXY"
android:src="@drawable/ic_error" />
</FrameLayout>
<FrameLayout
android:id="@+id/flid3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="160dp"
android:layout_marginTop="10dp"
android:focusable="false" >
<ImageView
android:id="@+id/itvimageid3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:focusable="true"
android:focusableInTouchMode="true"
android:scaleType="fitXY"
android:src="@drawable/ic_stub" />
</FrameLayout>
</RelativeLayout>
这里之所以用relativeLayout布局,而不用LinearLayout布局直接放入这三个FrameLayout,因为在之后的IncreaseActivity用到了一个方法bringToFront(),关于这个方法,之后讲解。
最后是IncreaseActivity
package com.example.test;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnFocusChangeListener;
import android.view.animation.Animation;
import android.widget.FrameLayout;
import android.widget.ImageView;
public class IncreaseActivity extends Activity implements OnClickListener {
public static final int COLUMN_IMAGE_COUNT = 3;
ImageView columnImages[] = new ImageView[COLUMN_IMAGE_COUNT];
FrameLayout mFrameLayout[]=new FrameLayout[COLUMN_IMAGE_COUNT];
ScaleAnimEffect animEffect = new ScaleAnimEffect();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_increase);
findviewbyid();
//给图片注册焦点改变监听
for (int i = 0; i < COLUMN_IMAGE_COUNT; i++) {
columnImages[i].setOnFocusChangeListener(focusChangeListener);
columnImages[i].setOnClickListener(this);
}
}
public void findviewbyid() {
columnImages[0] = (ImageView) findViewById(R.id.itvimageid1);
columnImages[1] = (ImageView) findViewById(R.id.itvimageid2);
columnImages[2] = (ImageView) findViewById(R.id.itvimageid3);
mFrameLayout[0] = (FrameLayout) findViewById(R.id.flid1);
mFrameLayout[1] = (FrameLayout) findViewById(R.id.flid2);
mFrameLayout[2] = (FrameLayout) findViewById(R.id.flid3);
}
@Override
public void onClick(View v) {
}
private OnFocusChangeListener focusChangeListener=new OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
switch(v.getId()){
case R.id.itvimageid1:
if (hasFocus) {
showOnFocusAnimation(0);
return;
}
showLooseFocusAinimation(0);
return;
case R.id.itvimageid2:
if (hasFocus) {
showOnFocusAnimation(1);
return;
}
showLooseFocusAinimation(1);
return;
case R.id.itvimageid3:
if (hasFocus) {
showOnFocusAnimation(2);
return;
}
showLooseFocusAinimation(2);
return;
}
}
};
/**
* 获取焦点后执行的方法
* @param i
*/
private void showOnFocusAnimation(int i) {
//将该控件移到最前面
mFrameLayout[i].bringToFront();
this.animEffect.setAttributs(1.0F, 1.25F, 1.0F, 1.25F, 100L);
Animation localAnimation = this.animEffect.createAnimation();
this.mFrameLayout[i].startAnimation(localAnimation);
}
/**
* 失去焦点后执行的方法
* @param i
*/
private void showLooseFocusAinimation(int i) {
animEffect.setAttributs(1.25F, 1.0F, 1.25F, 1.0F, 0L);
mFrameLayout[i].startAnimation(animEffect.createAnimation());
}
}
关于这里的bringToFront()方法,Android中的ViewGroup是通过一个Array来保存其Children,当调用某个childView的bringToFront时,是将该childView放在其Parent的Array数组的最后,ViewGroup的dispatchDraw在draw时是按照Array从前往后依次调用drawChild的,这样最后一个childView就在最前面了。这也是为什么要用relativeLayout来布局,而不是用LinearLayout来布局。
如果是LinearLayout布局,调用bringToFront方法,位置会错乱,你可以自己去试试。