您的位置:首页 > 移动开发 > Android开发

Android高级应用开发(深入篇) stage3(下)- 高级商用界面开发 学习笔记

2014-03-03 15:14 806 查看
动画

动画实质是什么 ?

Android动画实现机制

Android动画分类及编写方式



Property Animation属性动画是通过修改元素的属性值产生动画效果,需要3.0以上才能支持

View Animtion视图动画:只能作用在视图上,也称为Tween Animation

Drawable Animation:一帧一帧的显示图片资源,也称为Frame Animation

动画可不影响其他控件



动画有一个很重要的类,Transformation



我们换算,总要知道换算的是什么东西,所以还有一个重要的类Animation



通过Animation这个类定义动画模型或动画参数,传入到Transformation中进行运算,再由View呈现出来

View类中也有startAnimation和setAnimation方法设置动画

public class MainActivity extends Activity {

Button mButtonAlpha;
Button mButtonRotate;
Button mButtonScale;
Button mButtonTranslate;
Button mButtonComplex;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

mButtonAlpha = (Button)findViewById(R.id.button_alpha);
mButtonRotate = (Button)findViewById(R.id.button_rotate);
mButtonScale = (Button)findViewById(R.id.button_scale);
mButtonTranslate = (Button)findViewById(R.id.button_translate);
mButtonComplex = (Button)findViewById(R.id.button_complex);

mButtonAlpha.setOnClickListener(new AnimationListener(AnimationType.Alpha));
mButtonRotate.setOnClickListener(new AnimationListener(AnimationType.Rotate));
mButtonScale.setOnClickListener(new AnimationListener(AnimationType.Scale));
mButtonTranslate.setOnClickListener(new AnimationListener(AnimationType.Translate));
mButtonComplex.setOnClickListener(new AnimationListener(AnimationType.conplex));
}

enum AnimationType{
Alpha,
Rotate,
Scale,
Translate,
conplex
}

class AnimationListener implements OnClickListener{

private AnimationType mAnimationType;
public AnimationListener(AnimationType animationType){
mAnimationType = animationType;
}

@Override
public void onClick(View view) {
switch (mAnimationType){
case Alpha:
Log.i("Animation demo", "alpha");

// 定义动画
/**
* public AlphaAnimation(float fromAlpha, float toAlpha)
* fromAlpha: 开始时的alpha值
* toAlpha: 结束时的alpha值
*/
Animation alphaAnimation = new AlphaAnimation(1.0f, 0.1f);
alphaAnimation.setDuration(1000);
alphaAnimation.setFillBefore(true); // 动画结束停止在起始的样子
// alphaAnimation.setFillAfter(true); // 动画结束停止在结束的样子
alphaAnimation.setRepeatCount(1); // 动画重复次数
alphaAnimation.setRepeatMode(Animation.REVERSE); // 重复模式
alphaAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {

}

@Override
public void onAnimationEnd(Animation animation) {

}

@Override
public void onAnimationRepeat(Animation animation) {

}
});

// 启动动画
mButtonAlpha.startAnimation(alphaAnimation);

break;
case Rotate:

Log.i("Animation demo", "rotate");

// 定义动画
/**
* public RotateAnimation(float fromDegrees, float toDegrees,
*     int pivotXType, float pivotXValue, int pivotYType, float pivotYValue)
*
* fromDegrees: 起始时的角度
* toDegrees:结束时的角度
* pivotXType、pivotYValue:有Animation.ABSOLUTE、Animation.RELATIVE_TO_SELF、Animation.RELATIVE_TO_PARENT,轴的参照物
* pivotXValue、pivotYType:轴距离参照物的坐标,值在0~1之间,1表示100%
*/
Animation rotateAnimation = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 1, Animation.RELATIVE_TO_SELF, 0);
rotateAnimation.setDuration(1000);
rotateAnimation.setRepeatCount(1);
rotateAnimation.setRepeatMode(Animation.REVERSE);

// 启动动画
// mButtonRotate.setAnimation(rotateAnimation); // 只是设置了动画,不会立即启动
mButtonRotate.startAnimation(rotateAnimation);

break;
case Scale:

// 定义动画
/**
* public ScaleAnimation(float fromX, float toX, float fromY, float toY,
* int pivotXType, float pivotXValue, int pivotYType, float pivotYValue)
*/
Animation scaleAnimation = new ScaleAnimation(1, 1.5f, 1, 1.5f, Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0);
scaleAnimation.setDuration(1000);
scaleAnimation.setRepeatCount(1);
scaleAnimation.setRepeatMode(Animation.REVERSE);

// 启动动画
mButtonScale.startAnimation(scaleAnimation);

break;
case Translate:

// 定义动画
/**
* public TranslateAnimation(int fromXType, float fromXValue, int toXType, float toXValue,
*                          int fromYType, float fromYValue, int toYType, float toYValue)
*/
Animation translateAnimation = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 2,
Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 2);
translateAnimation.setDuration(1000);
translateAnimation.setRepeatCount(1);
translateAnimation.setRepeatMode(Animation.REVERSE);

// 启动动画
mButtonTranslate.startAnimation(translateAnimation);

break;
case conplex:

// 动画集,能综合Tween Animation的效果,参数为是否共享Interpolator
AnimationSet sets = new AnimationSet(false);

Animation alpha = new AlphaAnimation(1.0f, 0.1f);
alpha.setDuration(1000);
alpha.setRepeatCount(1); // 动画重复次数
alpha.setRepeatMode(Animation.REVERSE); // 重复模式

Animation rotate = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 1, Animation.RELATIVE_TO_SELF, 0);
rotate.setDuration(1000);
rotate.setRepeatCount(1);
rotate.setRepeatMode(Animation.REVERSE);

Animation scale = new ScaleAnimation(1, 1.5f, 1, 1.5f, Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0);
scale.setDuration(1000);
scale.setRepeatCount(1);
scale.setRepeatMode(Animation.REVERSE);

Animation translate = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 2,
Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 2);
translate.setDuration(1000);
translate.setRepeatCount(1);
translate.setRepeatMode(Animation.REVERSE);

sets.addAnimation(alpha);
sets.addAnimation(rotate);
sets.addAnimation(scale);
sets.addAnimation(translate);

mButtonComplex.startAnimation(sets);

break;
default:

break;
}
}
}

private OnClickListener onTextClickListener = new OnClickListener() {
@Override
public void onClick(View view) {

}
};
}


使用配置文件也能实现相同的效果(TweenAnimation)

在res\anim文件夹下配置xml



<?xml version="1.0" encoding="utf-8"?>

<set xmlns:android="http://schemas.android.com/apk/res/android">

<alpha
android:fromAlpha="1"
android:toAlpha="0.1"
android:duration="1000"
android:repeatCount="1"
android:repeatMode="reverse"/>

</set>


使用xml文件

// from XML
AnimationSet animationSet = (AnimationSet)AnimationUtils.loadAnimation(MainActivity.this, R.anim.my_animation);
mButtonXml.startAnimation(animationSet);


FrameAnimation也可以使用配置文件进行设定

但是不是放在res\anim文件夹下,而是在drawable文件夹下



<?xml version="1.0" encoding="utf-8"?>

<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/drawable1" android:duration="200" />
<item android:drawable="@drawable/drawable2" android:duration="200" />
<item android:drawable="@drawable/drawable3" android:duration="200" />
<item android:drawable="@drawable/drawable4" android:duration="200" />
<item android:drawable="@drawable/drawable5" android:duration="200" />
<item android:drawable="@drawable/drawable6" android:duration="200" />
</animation-list>


注意根节点是<animation-list>

使用时:

public class AnimationListActivity extends Activity {

private ImageView mImageView;
private AnimationDrawable animationDrawable;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.frame_animation);

mImageView = (ImageView)findViewById(R.id.imageView);

// 设置背景为动画列表
mImageView.setBackgroundResource(R.drawable.frame_drawable);
animationDrawable = (AnimationDrawable)mImageView.getBackground();

mImageView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
animationDrawable.setOneShot(true); // 只运行一次,不循环
animationDrawable.start();
}
});
}

}


AnimationDrawable间接继承自Drawable,实际上是一个Drawable容器



还能实现3D的旋转

平面旋转是以X轴和Y轴进行的旋转

而3D的旋转是Z轴的旋转

可以找一些例子看一下

Interpolator

是一个用来改变动画的速度比率的接口(针对TweenAnimation动画)

Interpolator定义了动画的执行过程中会如何改变。



下面的实现子类可以实现不同的速率模式

使用的方法也很简单

可以在配置文件中配置



也可以在代码中实现



AnimationSet构造器的参数是本动画集合下的动画是否共享定义的Interpolator

如果设为true,则共享同一个Interpolator,如果设为false,则需要各自定义各自的Interpolator

总结使用方法

1、创建动画

(1)在xm中定义

动画效果的定义应放在 res\anim目录下。

以下这两段段代码,通过在x轴连续7次的横向移动,实现了一个震动效果的动画:

cycle_7.xml

<cycleInterpolator xmlns:android="http://schemas.android.com/apk/res/android" android:cycles="7" />


shake.xml

<translate xmlns:android="http://schemas.android.com/apk/res/android" android:fromXDelta="0" android:toXDelta="10" android:duration="1000" android:interpolator="@anim/cycle_7" />


(2)通过代码创建

Animation anim = new TranslateAnimation(0, 10, 0, 0);
anim.setDuration(1000);
anim.setInterpolator(new CycleInterpolator(7));


这段代码同样实现了一个震动效果。

2、为View指定动画

通过调用View.startAnimation, 即可立即启动动画效果。

3、监控动画的执行状态

通过为动画设定AnimationListener,我们可以知道动画的执行状况:开始、完成、重复执行。

Android动画实现原理

图形变换通过矩阵实现。图形变换是图形学中的基本知识。简单来说就是,每种变换都是一次矩阵运算。

在 Android 中,Canvas 类中包含当前矩阵,当调用 Canvas.drawBitmap (bmp, x, y, Paint) 绘制时,

android 会先把 bmp 做一次矩阵运算,然后将运算的结果显示在 Canvas 上。

这样,编程人员只需不断修改 Canvas 的矩阵并刷新屏幕,

View 里的对象就会不停的做图形变换,动画就形成了。

实际上变换的是画布Canvas

动画运行模式

1、独占模式

即程序主线程进入一个循环,根据动画指令不断刷新屏幕,直到动画结束

2、中断模式

即有单独一个线程对时间计数,每隔一定的时间向主线程发通知,主线程接到通知后更新屏幕

Animation类

每个动画都重载了父类的 applyTransformation 方法,这个方法会被父类的 getTransformation 方法调用。

另外每个动画还有个 initialize 方法,完成初始化工作。



Interpolator类



Transformation类

Transformation 记录了仿射矩阵 Matrix,动画每触发一次,会对原来的矩阵做一次运算,

View 的 Bitmap 与这个矩阵相乘就可实现相应的操作(旋转、平移、缩放等)。

Transformation 类封装了矩阵和 alpha 值,它有两个重要的成员,一是 mMatrix,二是 mAlpha。



View中实现动画的过程

1、view 创建动画对象,设置动画属性,调用 invalidate 刷新屏幕,启动动画;

2、invalidate 方法触发了 onDraw 函数;

3、在 onDraw 函数中:

4、调用动画的 getTransformation 方法,得到当前时间点的矩阵

5、将该矩阵设置成 Canvas 的当前矩阵

6、调用 canvas 的 drawBitmap 方法,绘制屏幕。

7、判断 getTransformation 的返回值,若为真,调用 invalidate 方法,刷新屏幕进入下一桢;若为假,说明动画完成。



为Activity指定动画效果

修改Activity Theme

1. 在styles.xml中输入以下代码:

<style name="AnimationActivity" parent="@android:style/Animation.Activity" >
<item name="android:activityOpenEnterAnimation">@anim/push_left_in</item>
<item name="android:activityOpenExitAnimation">@anim/push_left_out</item>
<item name="android:activityCloseEnterAnimation">@anim/push_right_in</item>
<item name="android:activityCloseExitAnimation">@anim/push_right_out</item>
</style>


看一下定义的动画文件



2. 然后在themes.xml中

<style name="ThemeActivity">
<item name="android:windowAnimationStyle">@style/AnimationActivity</item>
<item name="android:windowNoTitle">true</item>
</style>


3. 在AndroidManifest.xml中为Activity指定theme.

或者也可以使用代码设定

通过调用 overridePendingTransition() 可以实时修改Activity的切换动画。

但需注意的是:该函数必须在调用startActivity()或finish()后立即调用,且只有效一次。

Drag

public class SimpleDragSample extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);
setContentView(R.layout.layout_simpledrag)  ;
DisplayMetrics dm = getResources().getDisplayMetrics()  ;
final int screenWidth = dm.widthPixels  ;
final int screenHeight = dm.heightPixels  ;
final Button _Button = (Button)findViewById(R.id.buttonDrag)  ;
_Button.setOnTouchListener(new OnTouchListener() {
int lastX , lastY  ;
boolean isDraging  = false  ;
@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub

int ea = event.getAction()  ;
switch (ea) {
case MotionEvent.ACTION_DOWN:
Log.i("sundylog","Down") ;
isDraging = true ;
lastX = (int) event.getRawX()  ;
lastY = (int) event.getRawY()  ;
break;
case MotionEvent.ACTION_MOVE:
if(isDraging)
{
int dx = (int)event.getRawX() - lastX  ;
int dy = (int)event.getRawY() - lastY  ;

int l = v.getLeft() + dx  ;
int b = v.getBottom() + dy  ;
int r = v.getRight() + dx  ;
int t = v.getTop() + dy  ;

//判断超出屏幕
if(l<0)
{
l = 0 ;
r = l + v.getWidth()  ;
}
if(t<0)
{
t = 0 ;
b = t + v.getHeight()  ;
}
if(r> screenWidth)
{
r = screenWidth  ;
l = r - v.getWidth()  ;
}
if(b > screenHeight)
{
b = screenHeight  ;
t = b - v.getHeight()  ;
}

v.layout(l, t, r, b)  ;
lastX = (int) event.getRawX()  ;
lastY = (int) event.getRawY()  ;
v.postInvalidate()  ;
}

break ;
case MotionEvent.ACTION_UP:
isDraging = false  ;
break ;
default:
break;
}
return false;
}
}) ;
}

}


如果想要按住时有一些效果,比如变大,等等,需要附加一个层,隐藏原来的View,这就需要用到shadow(DragShadow?)

还有如果想要一种吸附边缘的效果,就需要一些类似于单元格的容器(类似于GridView)

图片切换效果思路:

几个View叠在一起,切换时,上面的View在横向轴左移,-100%p(left-out),同时alpha值从1降到0

同时下一层View出现,从100%p进到主页面(right-in),同时alpha从0加到1,就实现了切换效果

系统也提供给我们一些相关的类,比如ViewAnimator

ViewAnimator有两个子类,ViewFlipper和ViewSwitcher

Sample:ViewFlipper实现最常见应用

1,定义四个动画 , fade_left_in fade_left_out fade_right_in fade_right_out

fade_left_in

<?xml version="1.0" encoding="utf-8"?>
<set  xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/accelerate_interpolator" android:shareInterpolator="true">
<alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="500" />
<translate android:fromXDelta="-100%p" android:toXDelta="0" android:duration="500"/>
</set>


fade_left_out

<?xml version="1.0" encoding="utf-8"?>
<set  xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/accelerate_interpolator" android:shareInterpolator="true">
<alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="500" />
<translate android:fromXDelta="0" android:toXDelta="-100%p" android:duration="500"/>
</set>


fade_right_in

<?xml version="1.0" encoding="utf-8"?>
<set  xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/accelerate_interpolator" android:shareInterpolator="true">
<alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="500" />
<translate android:fromXDelta="100%p" android:toXDelta="0" android:duration="500"/>
</set>


fade_right_out

<?xml version="1.0" encoding="utf-8"?>
<set  xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/accelerate_interpolator" android:shareInterpolator="true">
<alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="500" />
<translate android:fromXDelta="0" android:toXDelta="100%p" android:duration="500"/>
</set>


2,定义layout文件 。 <ViewAnimator> or <ViewFlipper>

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ViewFlipper android:id="@+id/viewFlipper1" android:layout_width="match_parent" android:layout_height="match_parent"
android:flipInterval="1000" android:inAnimation="@android:anim/fade_in" android:outAnimation="@android:anim/fade_out">
<FrameLayout android:layout_width="match_parent" android:id="@+id/frameLayout1" android:layout_height="match_parent">
<ImageView android:src="@drawable/gesture1" android:layout_height="match_parent" android:layout_width="match_parent"/>
</FrameLayout>
<FrameLayout android:id="@+id/frameLayout2" android:layout_width="match_parent" android:layout_height="match_parent">
<ImageView android:src="@drawable/gesture2" android:layout_height="match_parent" android:layout_width="match_parent"/>
</FrameLayout>
<FrameLayout android:id="@+id/frameLayout2" android:layout_width="match_parent" android:layout_height="match_parent">
<ImageView android:src="@drawable/gesture3" android:layout_height="match_parent" android:layout_width="match_parent"/>
</FrameLayout>
<FrameLayout android:id="@+id/frameLayout2" android:layout_width="match_parent" android:layout_height="match_parent">
<ImageView android:src="@drawable/gesture4" android:layout_height="match_parent" android:layout_width="match_parent"/>
</FrameLayout>
</ViewFlipper>

</LinearLayout>


说明:android:flipInterval 显示下一个视图的时间间隔

3,写代码 , onCreate() 取得Flipper对象设置好属性 。

4,事件 , GestureDetector .

5,onFling() , 设置 viewFlipper设置动画以及调用下一个ViewGroup

public class ViewFlipperActivity extends Activity implements GestureDetector.OnGestureListener {

ViewFlipper viewFlipper ;
GestureDetector gestureDetector ;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
gestureDetector = new GestureDetector(this)  ;
setContentView(R.layout.layout_viewflipper)  ;
viewFlipper = (ViewFlipper)findViewById(R.id.viewFlipper1)  ;

}

@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
//一定要加上
return gestureDetector.onTouchEvent(event) ;
}

@Override
public boolean onDown(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}

@Override
public void onShowPress(MotionEvent e) {
// TODO Auto-generated method stub

}

@Override
public boolean onSingleTapUp(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}

@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY) {
// TODO Auto-generated method stub
return false;
}

@Override
public void onLongPress(MotionEvent e) {
// TODO Auto-generated method stub

}

@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
// TODO Auto-generated method stub
Log.i("sundylog","onFling...")  ;
if(e1.getX() >e2.getX())
{
//如果是往左边滑动
//设置动画效果
viewFlipper.setOutAnimation(this, R.anim.fade_left_out)  ;
viewFlipper.setInAnimation(this,R.anim.fade_right_in)  ;
//上一张
viewFlipper.showPrevious()  ;
}else if(e1.getX() < e2.getX())
{
//如果是往右边滑动
viewFlipper.setOutAnimation(this,R.anim.fade_right_out)  ;
viewFlipper.setInAnimation(this,R.anim.fade_left_in)  ;
viewFlipper.showNext()  ;
}else
{
return false  ;
}
return true;
}

}


Activity的onTouchEvent一定要与GestureDetector绑定

当然也可以用某控件与GestureDetector绑定,仅对改控件手势有效

案例(模仿Apple程序列表的抖动效果)

Steps:

1, 通过PackageManager 加载应用图标到GridView里

2,定义好item的shake动画 , longclick的时候 , 启动动画

3,随着鼠标的移动 , 判断进入到了哪个Dock (哪个单元格区域)PointToPosition,从区域转换为index , 然后交换单元格视图(Swap)(先交换adapter ,绑定视图,视图就交换了)

4,Drop的时候把原来的图标放到当前单元格

具体看代码,有个ResolveInfo类是PackageManager中应用信息的结果

一共有五个类



ItemContainner

public class ItemContainer<T> extends FrameLayout implements AdapterView.OnItemLongClickListener,
View.OnTouchListener, ItemMover.OnImageMovedListener
{

private GridView             mGridView      = null;
private ItemMover           mItemMover     = null;
private ItemContainerAdapter<T> mAdapter   = null;

public ItemContainer(Context context)
{
this(context, null);
}

public ItemContainer(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
}

public ItemContainer(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
init();
}

private void init()
{
LayoutParams lp = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);

mGridView = new GridView(getContext());
mGridView.setGravity(Gravity.CENTER);
mGridView.setNumColumns(4);
addView(mGridView, lp);

mItemMover = new ItemMover(getContext());
addView(mItemMover, lp);

mGridView.setOnItemLongClickListener(this);
mGridView.setOnTouchListener(this);
mItemMover.setOnImageMoveListener(this);
}

protected void setNumColumns(int num) {
mGridView.setNumColumns(num);
}

public void setAdapter(ItemContainerAdapter<T> adapter)
{
mAdapter = adapter;
mGridView.setAdapter(adapter);
}

public void setOnItemClickListener(OnItemClickListener listener) {
mGridView.setOnItemClickListener(listener);
}

public ItemContainerAdapter<T>  getAdapter()
{
return mAdapter;
}

@Override
public boolean onItemLongClick(AdapterView<?> parent, View b, int pos,
long id)
{
mAdapter.setHideItem(pos);
View v = mAdapter.createSuspensionView(pos);
mItemMover.startMove(v);
return true;
}

@Override
public void onMoveStart(View v)
{
mGridView.invalidateViews();
}

@Override
public void onMoving(View v, float x, float y)
{
int targetPos = mGridView.pointToPosition((int) x, (int) y); // 通过坐标点转换为GridView单元格位置
int hiddenPos = mAdapter.getHideItemPosition();
if (hiddenPos != targetPos && targetPos >= 0)
{
if (mAdapter.swap(hiddenPos, targetPos))
{
mAdapter.setHideItem(targetPos);
refreshItem(targetPos);
onItemMoved(refreshItem(hiddenPos), hiddenPos, targetPos);
}
}
}

@Override
public void onMoveEnd(View v)
{
mAdapter.unhideAllItem();
mGridView.invalidateViews();
}

protected void onItemMoved(final View v, int oldPos, int newPos)
{
int oldCol = oldPos % 5;
int oldRow = oldPos / 5;

int newCol = newPos % 5;
int newRow = newPos / 5;

int w = v.getWidth();
int h = v.getHeight();

TranslateAnimation anim = new TranslateAnimation((newCol - oldCol) * w, 0.0f, (newRow - oldRow) * h, 0.0f);
anim.setDuration(300);
anim.setFillAfter(true);
anim.setAnimationListener(new Animation.AnimationListener(){

@Override
public void onAnimationEnd(Animation animation)
{
Animation mainAnim = AnimationUtils.loadAnimation(getContext(),
R.anim.shake);
v.setAnimation(mainAnim);
}

@Override
public void onAnimationRepeat(Animation animation)
{
}

@Override
public void onAnimationStart(Animation animation)
{
}});

v.setAnimation(anim);

}

@Override
public boolean onTouch(View v, MotionEvent event)
{
mItemMover.onTouchEvent(event);
return v.onTouchEvent(event);
}

private View refreshItem(int position)
{
int firstPos = mGridView.getFirstVisiblePosition();
int lastPos = mGridView.getLastVisiblePosition();
if (position >= firstPos && position <= lastPos )
{
View v = mGridView.getChildAt(position - firstPos);
mAdapter.bindView(v, position);
return v;
}
return null;
}

}


ItemContainerAdapter

public abstract class ItemContainerAdapter<T> extends BaseAdapter
{

private Context        mContext    = null;
protected List<T>        mItemList    = null;
private int            mHiddenPosition   = -1;

private final Random mRandom = new Random(SystemClock.currentThreadTimeMillis());

public ItemContainerAdapter(Context c, List<T> list)
{
mContext = c;
mItemList = list;
}

public void setHideItem(int pos)
{
int size = getCount();
if (pos >= 0 && pos < size)
{
mHiddenPosition = pos;
}
}

public int getHideItemPosition()
{
return mHiddenPosition;
}

public void unhideAllItem()
{
mHiddenPosition = -1;
}

public boolean swap(int a, int b)
{
if (a == b)
{
return false;
}
if (a < 0 || b < 0)
{
return false;
}
int size = getCount();
if (a >= size || b >= size)
{
return false;
}
T t = mItemList.get(a);
mItemList.set(a, mItemList.get(b));
mItemList.set(b, t);
return true;
}

public int getCount()
{
return mItemList.size();
}

@Override
public T getItem(int position)
{
return mItemList.get(position);
}

public long getItemId(int position)
{
return position;
}

abstract protected View onCreateItemView(int position, ViewGroup parent);

abstract public void onBindView(View v, int position);

abstract public void onHideView(View v);

public final void bindView(View v, int position) {
if (position == mHiddenPosition) {
onHideView(v);
} else {
v.setVisibility(View.VISIBLE);
v.clearAnimation();
onBindView(v, position);
}
}

public final View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = onCreateItemView(position, parent);
}

bindView(convertView, position);

if (mHiddenPosition >= 0 && position != mHiddenPosition) {
Animation anim = AnimationUtils.loadAnimation(mContext, R.anim.shake);
anim.setStartOffset(mRandom.nextInt() % anim.getDuration());
convertView.startAnimation(anim);
} else {
convertView.clearAnimation();
}
return convertView;
}

public final View createSuspensionView(int position) {
View v = onCreateItemView(position, null);
onBindView(v, position);
return v;
}
}


ItemMover

public class ItemMover extends FrameLayout
{
private OnImageMovedListener mOnImageMovedListener = null;

LayoutParams  mCurrentLayout = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);

public ItemMover(Context context)
{
super(context);
}

public ItemMover(Context context, AttributeSet attrs)
{
super(context, attrs);
}

public void setOnImageMoveListener(OnImageMovedListener l)
{
mOnImageMovedListener = l;
}

public void startMove(View v)
{
if (v == null)
{
return;
}

setVisibility(View.VISIBLE);
removeAllViews();

v.setVisibility(View.INVISIBLE);
v.clearAnimation();
addView(v);

if (mOnImageMovedListener != null)
{
mOnImageMovedListener.onMoveStart(v);
}

}

@Override
public boolean onTouchEvent(MotionEvent event)
{

View v = getChildAt(0);
if (v == null) {
return false;
}

switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// mDrawing = true;
break;
case MotionEvent.ACTION_UP:
// mDrawing = false;
if (getVisibility() == VISIBLE) {
setVisibility(GONE);
if (mOnImageMovedListener != null) {
mOnImageMovedListener.onMoveEnd(v);
}
}
break;
case MotionEvent.ACTION_MOVE:
break;
default:
break;
}
if (getVisibility() == VISIBLE) {
v.setVisibility(View.VISIBLE);

float x = event.getX() - 32;
float y = event.getY() - 32;

mCurrentLayout.setMargins((int)x, (int)y, 0, 0);
updateViewLayout(v, mCurrentLayout);
mOnImageMovedListener.onMoving(v, x, y);
return true;
} else {
mCurrentLayout.setMargins(0, 0, 0, 0);
return false;
}
}

public interface OnImageMovedListener {
public void onMoveStart(View v);
public void onMoving(View v, float x, float y);
public void onMoveEnd(View v);
}

}


ApplicationInfoContainer

public class ApplicationInfoContainer extends ItemContainer<ResolveInfo> {

public ApplicationInfoContainer(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);

TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.myAttr);
int numColumns = a.getInt(R.styleable.myAttr_numColumns, 0);
if (numColumns > 0) {
setNumColumns(numColumns);
}
}
}


ShakeDesktopActivity

public class ShakeDesktopActivity extends Activity implements OnItemClickListener
{

private LayoutInflater mInflater;
private PackageManager mPackageManager;

private ApplicationContainerAdapter mAdapter;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);

mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mPackageManager = getPackageManager();

requestWindowFeature(Window.FEATURE_NO_TITLE);
ApplicationInfoContainer container = new ApplicationInfoContainer(this, null, 0);
container.setAdapter(new ApplicationContainerAdapter(this));
container.setOnItemClickListener(this);
setContentView(container);
}

private class ApplicationContainerAdapter extends ItemContainerAdapter<ResolveInfo> {

ApplicationContainerAdapter(Context context) {
super(context, getAppInfoList(context));
}

@Override
public void onBindView(View v, int position) {
ResolveInfo info = mItemList.get(position);

ImageView image = (ImageView)v.findViewById(android.R.id.icon);
TextView text = (TextView)v.findViewById(android.R.id.text1);

image.setImageDrawable(info.activityInfo.loadIcon(mPackageManager));
text.setText(info.activityInfo.loadLabel(mPackageManager));
}

@Override
public void onHideView(View v) {
ImageView image = (ImageView)v.findViewById(android.R.id.icon);
TextView text = (TextView)v.findViewById(android.R.id.text1);

image.setImageResource(android.R.color.transparent);
text.setText("");
}

@Override
protected View onCreateItemView(int position, ViewGroup parent) {
View v = mInflater.inflate(R.layout.app_container_item, null);
return v;
}

};

private static List<ResolveInfo> getAppInfoList(Context context) {
PackageManager manager = context.getPackageManager();
Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
List<ResolveInfo> apps = manager.queryIntentActivities(mainIntent, 0);
Collections.sort(apps, new ResolveInfo.DisplayNameComparator(manager));
return apps;
}

@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id)
{
//Launch application
ResolveInfo info = mAdapter.getItem(position);
String packageName = info.activityInfo.packageName;
String activityName = info.activityInfo.name;

//        Intent intent = new Intent(Intent.ACTION_MAIN);
//        intent.addCategory(Intent.CATEGORY_LAUNCHER);
//        intent.setComponent(new ComponentName(packageName, activityName));
//        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
//                | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
//        mContext.startActivity(intent);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: