受Android4.0 滑动解锁波纹效果启发,模拟出HTC拉环解锁波浪。
上代码:
package com.android.internal.widget.htcmultiwaveview;
import java.util.ArrayList;
import com.android.internal.widget.multiwaveview.TargetDrawable;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import com.android.internal.R;
public class ChervonView extends View {
private static final int CHEVRON_INCREMENTAL_DELAY = 160;
private static final long CHEVRON_ANIMATION_DURATION = 650;
private static final String TAG = "ChervonView";
private int mFeedbackCount;
private ArrayList<TargetDrawable> mChevronDrawables = new ArrayList<TargetDrawable>();
private Drawable mTopChervonDrawable;
private ArrayList<Tweener> mChevronAnimations = new ArrayList<Tweener>();
private AnimatorUpdateListener mUpdateListener = new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator arg0) {
// TODO Auto-generated method stub
invalidate();
}
};
public ChervonView(Context context){
this(context,null);
}
public ChervonView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
Resources res = context.getResources();
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ChervonView);
mFeedbackCount = a.getInt(R.styleable.ChervonView_feedbackNumber, 4);
mTopChervonDrawable = a.getDrawable(R.styleable.ChervonView_topDrawable);
// Read chevron animation drawables
final int chevrons[] = { R.styleable.ChervonView_leftDrawable,
R.styleable.ChervonView_rightDrawable,
R.styleable.ChervonView_topDrawable,
R.styleable.ChervonView_bottomDrawable
};
for (int chevron : chevrons) {
Drawable chevronDrawable = a.getDrawable(chevron);
for (int i = 0; i < mFeedbackCount; i++) {
mChevronDrawables.add(
chevronDrawable != null ? new TargetDrawable(res, chevronDrawable) : null);
}
}
}
public void hideChevrons() {
for (TargetDrawable chevron : mChevronDrawables) {
if (chevron != null) {
chevron.setAlpha(0.0f);
}
}
}
/**
* Animation used to attract user's attention to the target button.
* Assumes mChevronDrawables is an a list with an even number of chevrons filled with
* mFeedbackCount items in the order: left, right, top, bottom.
*/
public void startChevronAnimation() {
final float mWaveCenterX = getWidth()/2;
final float mWaveCenterY = getHeight()-12;
final float r = mTopChervonDrawable.getIntrinsicWidth() * 0.4f;
final float chevronAnimationDistance = getHeight() * 0.1f;
final float from[][] = {
{mWaveCenterX - r, mWaveCenterY}, // left
{mWaveCenterX + r, mWaveCenterY}, // right
{mWaveCenterX, mWaveCenterY}, // top
{mWaveCenterX, mWaveCenterY + r} }; // bottom
final float to[][] = {
{mWaveCenterX - chevronAnimationDistance, mWaveCenterY}, // left
{mWaveCenterX + chevronAnimationDistance, mWaveCenterY}, // right
{mWaveCenterX, mWaveCenterY - chevronAnimationDistance}, // top
{mWaveCenterX, mWaveCenterY + chevronAnimationDistance} }; // bottom
mChevronAnimations.clear();
final float startScale = 1.0f;
final float endScale = 1.4f;
for (int direction = 0; direction < 4; direction++) {
for (int count = 0; count < mFeedbackCount; count++) {
int delay = count * CHEVRON_INCREMENTAL_DELAY;
final TargetDrawable icon = mChevronDrawables.get(direction*mFeedbackCount + count);
if (icon == null) {
continue;
}
mChevronAnimations.add(Tweener.to(icon, CHEVRON_ANIMATION_DURATION,
"ease", Ease.Quad.easeOut,
"delay", delay,
"x", new float[] { from[direction][0], to[direction][0] },
"y", new float[] { from[direction][1], to[direction][1] },
"alpha", new float[] {1.0f, 0.0f},
"scaleX", new float[] {startScale, endScale},
"scaleY", new float[] {startScale, endScale},
"onUpdate", mUpdateListener ));
}
}
}
public void stopChevronAnimation() {
for (Tweener anim : mChevronAnimations) {
anim.animator.end();
}
mChevronAnimations.clear();
}
private int resolveMeasured(int measureSpec, int desired) {
int result = 0;
int specSize = MeasureSpec.getSize(measureSpec);
switch (MeasureSpec.getMode(measureSpec)) {
case MeasureSpec.UNSPECIFIED:
result = desired;
break;
case MeasureSpec.AT_MOST:
result = Math.min(specSize, desired);
break;
case MeasureSpec.EXACTLY:
default:
result = specSize;
}
return result;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
// super.onMeasure(widthMeasureSpec, heightMeasureSpec);
final int minimumWidth = getSuggestedMinimumWidth();
final int minimumHeight = getSuggestedMinimumHeight();
Log.d(TAG,"____minimumWidth="+minimumWidth+", mininumHeight"+minimumHeight);
int viewWidth = resolveMeasured(widthMeasureSpec, minimumWidth);
int viewHeight = resolveMeasured(heightMeasureSpec, minimumHeight);
setMeasuredDimension(viewWidth, viewHeight);
}
@Override
protected int getSuggestedMinimumHeight() {
// TODO Auto-generated method stub
return (int) (mTopChervonDrawable.getIntrinsicHeight()*(1+0.2));
}
@Override
protected int getSuggestedMinimumWidth() {
// TODO Auto-generated method stub
return (int) (mTopChervonDrawable.getIntrinsicWidth()*(1+0.2));
}
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
// super.onDraw(canvas);
for (TargetDrawable target : mChevronDrawables) {
if (target != null) {
target.draw(canvas);
}
}
}
}
<com.android.internal.widget.htcmultiwaveview.ChervonView
android:id="@+id/htcChevron"
android:layout_width="250dip"
android:layout_height="150dip"
android:clickable="false"
android:topDrawable="@drawable/htc_ic_lockscreen_chevron_up"
android:feedbackCount="4"
android:focusable="false"
android:layout_gravity="bottom|center_horizontal"
/>