咖啡伴侣

呆在上海
posts - 163, comments - 156, trackbacks - 0, articles - 2

android手势效果-水果忍者 刀锋效果/光刀效果

Posted on 2011-09-23 11:29 oathleo 阅读(3935) 评论(5)  编辑  收藏 所属分类: Android
请保留:
http://www.blogjava.net/oathleo/archive/2011/09/23/android_Fruit_Ninja.html


android手势加上了,比如左右滑动
但是用户经常不能感受到是否滑动了,
水果忍者刀锋效果/光刀效果就相当不错

网上搜了下,大多是ios的实现,想想原理可能不是很复杂,就实现了个最简单的。
原理
1.在背景view上再加一层view专门负责draw刀锋
2.刀锋就是随着手势move,动态画shape
3.接受到事件得dispatchTouchEvent,否则下面的组件无法获得事件了
4.下面的组件事件等无需更改,互不耦合
5.一个类实现,不涉及其他第三方
6.只实现了一个最简单的形状,水果忍者里面实现了很多复杂形状,可以在这个基础上进行扩展
效果如图



代码:
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.view.MotionEvent;
import android.view.View;



/**
 * 
 * 模仿水果忍者刀锋效果
 * 
@author leooath@gmail.com
 *
 
*/
public class GestureView extends View {

    
private Paint paint;

    
private float startX = Float.NaN;
    
private float startY = Float.NaN;
    
private float endX = Float.NaN;
    
private float endY = Float.NaN;

    
//下层view
    private View viewer;
    
private static final int gestureColor = Color.rgb(153153153);
    
private static final int alpha = 220;
    
private static final int alpha_full = 255;
    
//刀锋长度
    private static final int shape_length = 40;
    
//刀锋截短时间
    private static final int shape_cut_time = 150;
    
    
public GestureView(Context context, View viewer) {
        
super(context);
        
this.viewer = viewer;
        paint 
= new Paint();
        paint.setStyle(Paint.Style.FILL);
    }

    
public void draw(Canvas canvas) {
        
super.draw(canvas);
        
if (!Float.isNaN(startX) && !Float.isNaN(endY)) {
            
float gap = ViewUtils.getGap(startX, startY, endX, endY);
            
float w = gap / 10;
            
//背景shape外侧点高度
            float h = w > 7 ? 7 : w;
            
//填充shape外侧点高度
            float h2 = h * 2 / 3

            
double length = Math.pow(Math.pow(w, 2+ Math.pow((h), 2), 0.5);
            
double length2 = Math.pow(Math.pow(w, 2+ Math.pow((h2), 2), 0.5);
            
            
double ang1_1 = Math.atan((endY - startY) / (endX - startX));
            
double ang1_2 = Math.atan(h / w);
            
double angle1_1 = ang1_1 + ang1_2;
            
double angle1_2 = ang1_1 - ang1_2;
            
            
double ang2_2 = Math.atan(h2 / w);
            
double angle2_1 = ang1_1 + ang2_2;
            
double angle2_2 = ang1_1 - ang2_2;
            
if (endX > startX) {
                
float xx1 = endX - (float) (length * Math.cos(angle1_1));
                
float yy1 = endY - (float) (length * Math.sin(angle1_1));
                
float xx2 = endX - (float) (length * Math.cos(angle1_2));
                
float yy2 = endY - (float) (length * Math.sin(angle1_2));

                
float xx12 = endX - (float) (length2 * Math.cos(angle2_1));
                
float yy12 = endY - (float) (length2 * Math.sin(angle2_1));
                
float xx22 = endX - (float) (length2 * Math.cos(angle2_2));
                
float yy22 = endY - (float) (length2 * Math.sin(angle2_2));
                
                Path backPath 
= new Path();
                backPath.moveTo(startX, startY);
                backPath.lineTo(xx1, yy1);
                backPath.lineTo(endX, endY);
                backPath.lineTo(xx2, yy2);
                backPath.close();
                
                Path fillPath 
= new Path();
                fillPath.moveTo(startX, startY);
                fillPath.lineTo(xx12, yy12);
                fillPath.lineTo(endX, endY);
                fillPath.lineTo(xx22, yy22);
                fillPath.close();

                paint.setColor(gestureColor);
                paint.setAlpha(alpha);
                canvas.drawPath(backPath, paint);
                
                paint.setColor(Color.WHITE);
                paint.setAlpha(alpha_full);
                canvas.drawPath(fillPath, paint);
            } 
else {
                
float xx1 = endX + (float) (length * Math.cos(angle1_1));
                
float yy1 = endY + (float) (length * Math.sin(angle1_1));
                
float xx2 = endX + (float) (length * Math.cos(angle1_2));
                
float yy2 = endY + (float) (length * Math.sin(angle1_2));

                
float xx12 = endX + (float) (length2 * Math.cos(angle2_1));
                
float yy12 = endY + (float) (length2 * Math.sin(angle2_1));
                
float xx22 = endX + (float) (length2 * Math.cos(angle2_2));
                
float yy22 = endY + (float) (length2 * Math.sin(angle2_2));
                
                Path backPath 
= new Path();
                backPath.moveTo(startX, startY);
                backPath.lineTo(xx1, yy1);
                backPath.lineTo(endX, endY);
                backPath.lineTo(xx2, yy2);
                backPath.close();

                Path fillPath 
= new Path();
                fillPath.moveTo(startX, startY);
                fillPath.lineTo(xx12, yy12);
                fillPath.lineTo(endX, endY);
                fillPath.lineTo(xx22, yy22);
                fillPath.close();

                paint.setColor(gestureColor);
                paint.setAlpha(alpha);
                canvas.drawPath(backPath, paint);
                
                paint.setColor(Color.WHITE);
                paint.setAlpha(alpha_full);
                canvas.drawPath(fillPath, paint);
            }
        }
    }

    
public boolean onTouchEvent(android.view.MotionEvent event) {
        
if(event.getPointerCount() == 1){
            
int action = event.getAction();
            
if (MotionEvent.ACTION_DOWN == action) {
                startX 
= event.getX();
                startY 
= event.getY();
            } 
else if (MotionEvent.ACTION_MOVE == action) {
                endX 
= event.getX();
                endY 
= event.getY();
                
                
//刀锋截短时间,则截短至一半
                if ((event.getEventTime() - event.getDownTime()) > shape_cut_time) {
                    
if(Math.abs(endX - startX) > shape_length && Math.abs(endY - startY) > shape_length){
                        startX 
= (float) (startX + (endX - startX) * 0.5);
                        startY 
= (float) (startY + (endY - startY) * 0.5);
                    }
                }

                invalidate();
            } 
else if (MotionEvent.ACTION_UP == action) {
                startX 
= Float.NaN;
                startY 
= Float.NaN;
                endX 
= Float.NaN;
                endY 
= Float.NaN;
                invalidate();
            }
        }
        
//该view消费了event,所以下层的view必须dispatchTouchEvent才能获得事件
        MotionEvent newEvent = MotionEvent.obtain(event);
        viewer.dispatchTouchEvent(newEvent);
        
return true;
    }

}

Feedback

# re: android手势效果-水果忍者 刀锋效果/光刀效果  回复  更多评论   

2011-09-25 23:23 by tbw
不错啊

# re: android手势效果-水果忍者 刀锋效果/光刀效果  回复  更多评论   

2011-09-28 16:45 by 优美科

ViewUtils.getGap(startX, startY, endX, endY);
函数呢 怎么没有

# re: android手势效果-水果忍者 刀锋效果/光刀效果  回复  更多评论   

2011-10-13 13:44 by oathleo
@优美科
/**
* 获得两点间距离
*/
public static final float getGap(float x0, float y0, float x1, float y1) {
return (float) Math.pow(Math.pow((x0 - x1), 2) + Math.pow((y0 - y1), 2), 0.5);
}

# re: android手势效果-水果忍者 刀锋效果/光刀效果[未登录]  回复  更多评论   

2012-03-24 20:22 by tobe
那请问怎样在一层view上加入这层半透明的view呢?

# re: android手势效果-水果忍者 刀锋效果/光刀效果  回复  更多评论   

2012-04-07 21:17 by banxi
请问下,我想实现水果忍者的切按钮的效果。也就是更进一步的效果如果处理。特向您请教下!

只有注册用户登录后才能发表评论。


网站导航: