一,闲来无事,写一个小东西练练手,首先看效果图
二,原理分析
图片缩放可以用Matrix,渐变可以用Paint的alpha,再加上根据滑动距离的检测,就可以实现效果
三,源码地址:http://download.csdn.net/detail/u012155141/8915515
四,步骤解析
1,自定义view,在构造方法中初始化一些属性
public TouchScalView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mMatrix = new Matrix();
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.bg_1);
mBitmap = bitmap;
viewWidth = mBitmap.getWidth();
viewHeight = mBitmap.getHeight();
mPaint = new Paint();
initInvisibleThread();
initVisibleThread();
}
2,重写onDraw,关键在于设置透明度和缩放比例
@Override
protected void onDraw(Canvas canvas) {
mPaint.setAlpha(alpha);
mMatrix.setScale((viewWidth + Radius) * 1f / viewWidth,
(viewHeight + Radius) * 1f / viewHeight,viewWidth/2,viewHeight/2);
canvas.drawBitmap(mBitmap, mMatrix, mPaint);
super.onDraw(canvas);
}
缩放比例为1时,就是原图大小,这里我们有一个变化的范围Radius,Radius在-viewWidth / 2和viewWidth/2中根据滑动距离变化。我们需要不停的
改变Radius的值,因此定义个接口,并对外公布一个方法,供调用。
public void setRadius(float dis) {
isFinished = false;
this.Radius += dis / 4;
if (Radius > viewWidth / 2) {
Radius = viewWidth / 2;
isFinished = true;
}
if (Radius < -viewWidth / 2) {
Radius = -viewWidth / 2;
isFinished = true;
}
if(mFinishListener != null){
mFinishListener.finished(isFinished);
}
alpha = (int) ((viewWidth / 2 + Radius) * 255 / viewWidth);
invalidate();
Log.i("AfterRadius", "" + Radius);
}
public interface FinishListener{
void finished(boolean isFinished);
}
public void setFinishListener(FinishListener listener){
this.mFinishListener = listener;
}
在构造方法中初始化时我们看到有两个方法,他们是当手松开时自动执行动画的两个显示,隐藏的线程
private void initVisibleThread() {
visibleThread = new Thread(){
@Override
public void run() {
while (Radius <viewWidth / 2) {
try {
sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
Radius++;
if (Radius > viewWidth / 2) {
Radius = viewWidth / 2;
}
alpha = (int) ((viewWidth / 2 + Radius) * 255 / viewWidth);
postInvalidate();
}
}
};
}
private void initInvisibleThread() {
inVisibleThread = new Thread(){
@Override
public void run() {
while (Radius >-viewWidth / 2) {
try {
sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
Radius--;
if (Radius <-viewWidth / 2) {
Radius = -viewWidth / 2;
}
alpha = (int) ((viewWidth / 2 + Radius) * 255 / viewWidth);
postInvalidate();
}
}
};
}
ok,自定义的view完成,接下来就是在ontouchEvent中处理,首先,当手指按下滑动时我们用GestureDetector来处理,在onscroll方法中回调我们的接口
class IGestureDetector implements OnGestureListener{
@Override
public boolean onDown(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
// TODO Auto-generated method stub
return false;
}
@Override
public void onLongPress(MotionEvent e) {
// TODO Auto-generated method stub
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
if(Math.abs(distanceY)<Math.abs(distanceX)/3){
mTouchScalView.setRadius(distanceX);
}
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;
}
}
接下来在手指松开时,我们根据速度来执行在view中的autoInVisibleAnimation和autoVisibleAnimation方法。
@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
Thread[] thds = mTouchScalView.getThreads();
Thread thread0 = thds[0];
Thread thread1 = thds[1];
if(thread0.isAlive() ||thread1.isAlive()){
return true;
}
mdDetector.onTouchEvent(event);
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();// 获得VelocityTracker类实例
}
mVelocityTracker.addMovement(event);// 将事件加入到VelocityTracker类实例中
mVelocityTracker.computeCurrentVelocity(1000);
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
downX = (int) event.getX();
break;
case MotionEvent.ACTION_UP:
int curX = (int) event.getX();
float xVelocity = Math.abs(mVelocityTracker.getXVelocity());
if (xVelocity > mMaximumVelocity) {
xVelocity = mMaximumVelocity;
}
if(!isFinished){
if(xVelocity>mMinimumVelocity){
if(curX - downX>0){
mTouchScalView.autoInVisibleAnimation();
} else if(curX - downX<0){
mTouchScalView.autoVisibleAnimation();
}
}
}
break;
case MotionEvent.ACTION_CANCEL:
mVelocityTracker.recycle();
break;
default:
break;
}
return true;
}