实现支付宝咻一咻的几种思路

来源:互联网 发布:winhex格式化数据恢复 编辑:程序博客网 时间:2024/06/05 00:13

对于现在最火的无外乎集五福了,而五福除了加十个好友获得外,最直接的途径就是支付宝的咻一咻了。那么咻一咻具体有哪些实现方式呢?下面我们将一一介绍这几种思路的实现过程。


1.自定义View实现咻一咻


那么这种实现方法需要掌握Canvas以及Paint几乎所有的方法。其对程序员的专业知识要求极高。


用该种方式实现的优点有:


㈠这种是最复杂的实现方法,但其兼容性最高,其支持android的所有设备。


㈡其对内存要求不大,几乎不占用任何内存。


下面我们来看看是怎样实现其效果的:


public class XiuYiXiuView extends View {    /***     * 中心图片画笔     */    private Paint paint;    /***     * 水波圆圈画笔     */    private Paint circlePaint;    /***     * 用bitmap创建画布     */    private Bitmap bitmap;    /***     * 中心图片     */    private Bitmap imageBit;    /***     * 画布     */    private Canvas canvas;    /***     * 屏幕的宽     */    private int screenWidth;    /***     * 屏幕的高     */    private int screenHeight;    /***     * 图片右上角坐标     */    private Point pointLeftTop;    /***     * 图片右下角坐标     */    private Point pointRightBottom;    /***     * 记录圆圈     */    private List<LYJCircle> lyjCircleList;    /***     * 标记是否按下按钮,并且源泉是否扩散消失     */    private boolean isSpread=false;    /***     * 默认没有按动时候的圆圈     */    private LYJCircle defaultCircle;    public XiuYiXiuView(Context context, AttributeSet attrs) {        super(context, attrs);        this.lyjCircleList=new ArrayList<>();        screenWidth=LYJUtils.getScreenWidth((Activity) context);        screenHeight=LYJUtils.getScreenHeight((Activity) context);        bitmap = Bitmap.createBitmap(screenWidth, screenHeight, Bitmap.Config.ARGB_8888); // 设置位图的宽高        canvas = new Canvas();        canvas.setBitmap(bitmap);        paint=new Paint(Paint.DITHER_FLAG);        paint.setAntiAlias(true);        circlePaint=new Paint(Paint.DITHER_FLAG);        circlePaint.setAntiAlias(true);        imageBit= BitmapFactory.decodeResource(getResources(), R.drawable.bwa_homepage_yuyin);        pointLeftTop=new Point((screenWidth/2)-(imageBit.getWidth()/2),(screenHeight/2)-(imageBit.getHeight()/2));        pointRightBottom=new Point(pointLeftTop.x+imageBit.getWidth(),pointLeftTop.y+imageBit.getHeight());        canvas.drawBitmap(imageBit,pointLeftTop.x,pointLeftTop.y,paint);        //取图片上的颜色        Palette.generateAsync(imageBit, new Palette.PaletteAsyncListener() {            @Override            public void onGenerated(Palette palette) {                Palette.Swatch swatch1 = palette.getVibrantSwatch(); //充满活力的色板                circlePaint.setColor(swatch1.getRgb());                circlePaint.setStyle(Paint.Style.STROKE);                circlePaint.setStrokeWidth(10);                circlePaint.setAlpha(100);                paint.setShadowLayer(15, 0, 0, swatch1.getRgb());//设置阴影效果                int[] mColors = new int[] {//渲染颜色                        Color.TRANSPARENT,swatch1.getRgb()                };                //范围,这里可以微调,实现你想要的渐变                float[] mPositions = new float[] {                        0f, 0.1f                };                Shader shader=new RadialGradient(screenWidth / 2,screenHeight / 2,imageBit.getWidth() / 2 + 10,mColors, mPositions,                        Shader.TileMode.MIRROR);                circlePaint.setShader(shader);                defaultCircle=new LYJCircle(screenWidth / 2, screenHeight / 2, imageBit.getWidth() / 2 + 10);                clearScreenAndDrawList();                Message message = handler.obtainMessage(1);                handler.sendMessageDelayed(message, 1000); //发送message            }        });    }    @Override    public boolean onTouchEvent(MotionEvent event) {        switch (event.getAction()){            case MotionEvent.ACTION_DOWN:                break;            case MotionEvent.ACTION_MOVE:                break;            case MotionEvent.ACTION_UP:                isSpread=true;//是否按下图片                lyjCircleList.add(new LYJCircle(screenWidth / 2, screenHeight / 2, imageBit.getWidth() / 2 + 10));                clearScreenAndDrawList();                invalidate();                break;            default:                break;        }        return true;    }    private Handler handler = new Handler(){        public void handleMessage(Message msg){            switch (msg.what) {                case 1:                    //定时更新界面                    clearScreenAndDrawList();                    invalidate();                    Message message = handler.obtainMessage(1);                    handler.sendMessageDelayed(message, 200);            }            super.handleMessage(msg);        }    };    /**     * 清掉屏幕上所有的圆圈,然后画出集合里面的圆圈     */    private void clearScreenAndDrawList() {        canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);        //判断是否按下图片,并且外圈执行完成没有。        if(!isSpread){                circlePaint.setMaskFilter(null);                canvas.drawCircle(defaultCircle.getRoundX(), defaultCircle.getRoundY(),defaultCircle.getRadiuLoop(), circlePaint);// 画线        }else{            for (LYJCircle lyjCircle : lyjCircleList) {                if(lyjCircle.getSpreadRadiu()==0){                }else if(lyjCircle.getSpreadRadiu()>(lyjCircle.getRadiu()+99)){                    //如果圆圈扩散半径大于图片半径+99,那么设置边缘模糊,也就是淡出的效果                    circlePaint.setMaskFilter(new BlurMaskFilter(5, BlurMaskFilter.Blur.OUTER));                    canvas.drawCircle(lyjCircle.getRoundX(), lyjCircle.getRoundY(),lyjCircle.getSpreadRadiu(), circlePaint);// 画线                }else{                    //不是则按正常的环形渲染来                    circlePaint.setMaskFilter(null);                    canvas.drawCircle(lyjCircle.getRoundX(), lyjCircle.getRoundY(),lyjCircle.getSpreadRadiu(), circlePaint);// 画线                }            }        }        canvas.drawBitmap(imageBit,pointLeftTop.x,pointLeftTop.y,paint);        //释放小时了的圆圈        for(int i=0;i<lyjCircleList.size();i++){            if(lyjCircleList.get(i).getSpreadRadiu()==0){                lyjCircleList.remove(i);            }        }        //如果没有点击图片发射出去的圆圈,那么就恢复默认缩放。        if(lyjCircleList.size()<=0){            isSpread=false;        }    }    @Override    protected void onDraw(Canvas canvas) {        canvas.drawBitmap(bitmap, 0, 0, null);    }}

圆类:


package com.example.liyuanjing.model;/** * Created by liyuanjing on 2016/2/3. */public class LYJCircle {    private int roundX;//圆中心点X坐标    private int roundY;//圆中心点Y坐标    private int radiu;//圆半径    private int currentRadiu;//当前radiu    private int lastRadiu;//历史radiu    private int spreadRadiu;//加速半径    private int[] speed=new int[]{6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6};//半径扩大速度。这里为匀速    private int speedLast=0;//记录历史值    public LYJCircle(int roundX,int roundY,int radiu){        this.roundX=roundX;        this.roundY=roundY;        this.radiu=radiu;        this.spreadRadiu=radiu;        this.currentRadiu=this.radiu;        this.lastRadiu=this.currentRadiu;    }    //获取半径    public int getRadiu() {        return radiu;    }    public void setRadiu(int radiu) {        this.radiu = radiu;    }    //获取加速半径    public int getSpreadRadiu(){        if(speedLast>=speed.length){            return 0;        }        spreadRadiu+=speed[speedLast];        ++speedLast;        return spreadRadiu;    }    //获取循环缩放半径    public int getRadiuLoop() {        if(currentRadiu==lastRadiu){            ++currentRadiu;        }else if(currentRadiu>lastRadiu){            if(currentRadiu>(radiu+20)){                currentRadiu=19+radiu;                lastRadiu=20+radiu;            }else{                lastRadiu=currentRadiu;                currentRadiu+=5;            }        }else{            if(currentRadiu<(radiu+9)){                currentRadiu=10+radiu;                lastRadiu=9+radiu;            }else{                lastRadiu=currentRadiu;                currentRadiu-=5;            }        }        return currentRadiu;    }    public int getRoundX() {        return roundX;    }    public int getRoundY() {        return roundY;    }}


看看其效果图:




你可以修改如下两个地方,会产生视觉上真真的波纹效果:


①支付宝的背景图片是淡红色,衬托了红色的波纹。当然了你也可以将画布设置为透明淡红色。


②其为填充圆圈渲染,不是我的边框渲染效果,你可以将circlePaint.setStyle(Paint.Style.STROKE);换成Paint.Style.FILL.然后,微调shader的mPositions实现环形填充渐变。你也许会觉得,你看支付宝咻一咻圆圈弹开的时候内圈有波纹也像外弹开,其实那就是环形渐变,当你圆圈变大后,其渐变的范围也就变大了,自然你看到有颜色周围扩散的迹象。


2.属性动画实现咻一咻


其要掌握的只是基本只需要属性动画,在加一点线程方面有关的知识而已。


下面我们看看其实现步骤:


㈠自定义View实现一个圆即可,代码如下:


public class LYJCircleView extends View {    private Bitmap bitmap;    private Paint paint;    private Canvas canvas;    private int screenWidth;    private int screenHeight;    private boolean isSpreadFlag=false;//标记是否发射完成    public boolean isSpreadFlag() {        return isSpreadFlag;    }    public void setIsSpreadFlag(boolean isSpreadFlag) {        this.isSpreadFlag = isSpreadFlag;    }    public LYJCircleView(Context context,int width,int height,int statusHeight) {        super(context);        screenWidth= LYJUtils.getScreenWidth((Activity) context);        screenHeight=LYJUtils.getScreenHeight((Activity) context);        bitmap = Bitmap.createBitmap(screenWidth, screenHeight, Bitmap.Config.ARGB_8888); // 设置位图的宽高        canvas = new Canvas();        canvas.setBitmap(bitmap);        paint=new Paint(Paint.DITHER_FLAG);        paint.setAntiAlias(true);        paint.setColor(Color.RED);        paint.setStyle(Paint.Style.STROKE);        paint.setStrokeWidth(5);        paint.setAlpha(100);        paint.setShadowLayer(10, 0, 0, Color.RED);        int[] mColors = new int[] {                Color.TRANSPARENT,Color.RED        };        float[] mPositions = new float[] {                0f, 0.1f        };        Shader shader=new RadialGradient(screenWidth / 2,screenHeight / 2,width / 2 + 10,mColors, mPositions,                Shader.TileMode.MIRROR);        paint.setShader(shader);        canvas.drawCircle(screenWidth / 2, (screenHeight - statusHeight) / 2, width / 2 + 10, paint);        invalidate();    }    @Override    protected void onDraw(Canvas canvas) {        canvas.drawBitmap(bitmap,0,0,null);    }}

代码与上面差不多,就不注释了。



㈡实现Activity即可


public class XiuYiXiuActivity extends AppCompatActivity {    private ImageButton mImageButton;    private LYJCircleView lyjCircleView;    private RelativeLayout relativeLayout;    private List<LYJCircleView> lyjCircleViewList;    private int statusBarHeight;    private Animator anim;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.xiuyixiu_activity_main);        this.mImageButton=(ImageButton)findViewById(R.id.xiuyixiu_imagebutton);        this.relativeLayout=(RelativeLayout)findViewById(R.id.xiuyixiu_relativelayout);        this.lyjCircleViewList=new ArrayList<>();        this.mImageButton.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                lyjCircleView.setVisibility(View.GONE);//发射圆圈,即将循环动画View隐藏                final LYJCircleView item=new LYJCircleView(XiuYiXiuActivity.this, mImageButton.getWidth(), mImageButton.getHeight(), statusBarHeight);                Animator spreadAnim = AnimatorInflater.loadAnimator(XiuYiXiuActivity.this, R.animator.circle_spread_animator);                spreadAnim.addListener(new Animator.AnimatorListener() {                    @Override                    public void onAnimationStart(Animator animation) {                    }                    @Override                    public void onAnimationEnd(Animator animation) {                        item.setIsSpreadFlag(true);//动画执行完成,标记一下                    }                    @Override                    public void onAnimationCancel(Animator animation) {                    }                    @Override                    public void onAnimationRepeat(Animator animation) {                    }                });                spreadAnim.setTarget(item);                spreadAnim.start();                lyjCircleViewList.add(item);                relativeLayout.addView(item);                relativeLayout.invalidate();                Message message = handler.obtainMessage(1);                handler.sendMessageDelayed(message, 10); //发送message,定时释放LYJCircleView            }        });    }    private Handler handler = new Handler(){        public void handleMessage(Message msg){            switch (msg.what) {                case 1:                    for(int i=0;i<lyjCircleViewList.size();i++){                        if(lyjCircleViewList.get(i).isSpreadFlag()){                            relativeLayout.removeView(lyjCircleViewList.get(i));                            lyjCircleViewList.remove(i);                            relativeLayout.invalidate();                        }                    }                    if(lyjCircleViewList.size()<=0){                        lyjCircleView.setVisibility(View.VISIBLE);                    }                    Message message = handler.obtainMessage(1);                    handler.sendMessageDelayed(message, 10);            }            super.handleMessage(msg);        }    };    @Override    public void onWindowFocusChanged(boolean hasFocus) {        super.onWindowFocusChanged(hasFocus);        //获取状态栏高度        Rect frame = new Rect();        getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);        statusBarHeight = frame.top;        this.mImageButton.post(new Runnable() {            @Override            public void run() {                lyjCircleView = new LYJCircleView(XiuYiXiuActivity.this, mImageButton.getWidth(), mImageButton.getHeight(), statusBarHeight);                relativeLayout.addView(lyjCircleView);                relativeLayout.postInvalidate();                // 加载动画                anim = AnimatorInflater.loadAnimator(XiuYiXiuActivity.this, R.animator.circle_scale_animator);                anim.addListener(new Animator.AnimatorListener() {                    @Override                    public void onAnimationStart(Animator animation) {                    }                    @Override                    public void onAnimationEnd(Animator animation) {                        anim.start();//循环执行动画                    }                    @Override                    public void onAnimationCancel(Animator animation) {                    }                    @Override                    public void onAnimationRepeat(Animator animation) {                    }                });                anim.setTarget(lyjCircleView);                anim.start();            }        });    }}

㈢布局文件代码如下:


<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:id="@+id/xiuyixiu_relativelayout"    android:layout_width="match_parent"    android:layout_height="match_parent">    <ImageButton        android:id="@+id/xiuyixiu_imagebutton"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_centerInParent="true"        android:background="@drawable/bwa_homepage_yuyin"/></RelativeLayout>

当然上面两个实现方法,我都只设置圆边框,没有填充,你可以设置为填充后,在微调渐变值。


其属性动画文件circle_scale_animator.xml:


<?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android"    android:ordering="together">    <objectAnimator        android:duration="1000"        android:propertyName="scaleX"        android:valueFrom="1.0"        android:valueTo="1.2"        android:valueType="floatType">    </objectAnimator>    <objectAnimator        android:duration="1000"        android:propertyName="scaleY"        android:valueFrom="1.0"        android:valueTo="1.2"        android:valueType="floatType">    </objectAnimator>    <objectAnimator        android:startOffset="1000"        android:duration="1000"        android:propertyName="scaleX"        android:valueFrom="1.2"        android:valueTo="1.0"        android:valueType="floatType">    </objectAnimator>    <objectAnimator        android:startOffset="1000"        android:duration="1000"        android:propertyName="scaleY"        android:valueFrom="1.2"        android:valueTo="1.0"        android:valueType="floatType">    </objectAnimator></set>

另一个circle_spread_animator.xml为:


<?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android">    <objectAnimator        android:duration="1000"        android:propertyName="scaleY"        android:valueFrom="1.0"        android:valueTo="2.0"        android:valueType="floatType">    </objectAnimator>    <objectAnimator        android:duration="1000"        android:propertyName="scaleX"        android:valueFrom="1.0"        android:valueTo="2.0"        android:valueType="floatType">    </objectAnimator></set>


其效果图如下:




3.Android 5.0逆天实现咻一咻


这个仅标记出来,不做讲解,不过有几个知识提示一下,你就明白了,不过此种方式实现只兼容5.0以上设备,不兼容5.0以下设备。


我们都知道5.0中提供如下两个属性:


android:background="?android:attr/selectableItemBackground"波纹有边界


android:background="?android:attr/selectableItemBackgroundBorderless"波纹超出边界


设置下面这个就会绘制一个圆形的波纹(不管你的控件是不是圆形)。


通过android:colorControlHighlight设置波纹颜色。


那么好了就,介绍这么多了,时间匆促,要过年了。最后附上本文源码:


https://github.com/liyuanjinglyj/XiuYiXiuDemo


16 1
原创粉丝点击