android 小船在 水波上移动

来源:互联网 发布:spark sql mongodb 编辑:程序博客网 时间:2024/04/29 15:57

最近有这么个需求看图如下:


要求船动 ,波动,船随波动

实际实现效果如下,勉强通过



分析解决方案:

1:做成帧动画,发现切了200多张图,我也是醉了,为了避免OOM,崩溃的原因,舍弃,再说图片将近40M

2:做成MP4,播放视频发现,小了许多8M,呵呵,但是依旧很大,再尝试的过程中,避免不了视频初始化加载会黑一下,或闪一下的问题,舍弃

3:最后只能采用绘制

于是网上各种搜索,各种学习开始了:

1:先实现一条波,并让其波动

package test.vko.cn.ttapplication.weight;import android.animation.ValueAnimator;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Path;import android.graphics.PathMeasure;import android.graphics.PointF;import android.util.AttributeSet;import android.view.View;import java.util.ArrayList;import java.util.List;import test.vko.cn.ttapplication.R;/** * Created by JiaRH on 2015/11/19. */public class ShipWaveView extends View {    Paint mPaint;    private int color = Color.parseColor("#50378DCC");    private int viewWidth;    private int viewHeight;    private  int WAVE_HEIGHT = 40;    private List<PointF> mPointsList;    private int mWaveWidth = 350;    private int mLevelLine;    private Path mWavePath;    private boolean isMeasured;    /**     * 记录当前运动点的位置     */    private float[] mCurrentPosition = new float[2];    private PathMeasure mPathMeature;    Bitmap boat;    ValueAnimator valueAnimator;    private int speed = 3;    private int moveLen = 0;    public ShipWaveView(Context context) {        this(context, null);    }    public ShipWaveView(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public ShipWaveView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        initData(context);        initPaint();    }    private void initData(Context context) {        mPointsList = new ArrayList<>();        boat = BitmapFactory.decodeResource(getResources(), R.drawable.boat1);    }    private void initPaint() {        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);        mPaint.setStrokeWidth(1.5f);        mPaint.setStyle(Paint.Style.FILL);        mWavePath = new Path();    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {//        int withSize = MeasureSpec.getSize(widthMeasureSpec);//        int heightSize = MeasureSpec.getSize(heightMeasureSpec);//        int withMode = MeasureSpec.getMode(widthMeasureSpec);//        int heightMode = MeasureSpec.getMode(heightMeasureSpec);//        if(withMode==MeasureSpec.AT_MOST&&heightMode==MeasureSpec.AT_MOST){//            withSize = getMeasuredWidth();//        }        super.onMeasure(widthMeasureSpec, heightMeasureSpec);    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        mWavePath.reset();        mWavePath.moveTo(mPointsList.get(0).x, mPointsList.get(0).y);        for (int i = 0; i < mPointsList.size() - 2; i = i + 2) {            mWavePath.quadTo(mPointsList.get(i + 1).x,                    mPointsList.get(i + 1).y, mPointsList.get(i + 2)                            .x, mPointsList.get(i + 2).y);        }        mWavePath.lineTo(viewWidth, 0);        mWavePath.lineTo(0, 0);        mWavePath.close();        mPathMeature = new PathMeasure(mWavePath, true);        drawPath(canvas);    }    private void drawPath(Canvas canvas) {        mPaint.setColor(color);//        mPaint.setColor(Color.TRANSPARENT);        // mPaint的Style是FILL,会填充整个Path区域        canvas.drawPath(mWavePath, mPaint);    }    @Override    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {        super.onLayout(changed, left, top, right, bottom);        viewWidth = getWidth();        viewHeight = getHeight();        mLevelLine = viewHeight/2;        if (!isMeasured) {            isMeasured = true;            int n = (int) Math.round(viewWidth / mWaveWidth + 0.5);//            n=1;            // n个波形需要4n+1个点,但是我们要预留一个波形在左边隐藏区域,所以需要4n+5个点            for (int i = 0; i < (4 * n + 5 + 4); i++) {                // 从P0开始初始化到P4n+4,总共4n+5个点                float x = i * mWaveWidth / 4 - mWaveWidth;//                float x = i * mWaveWidth / 4;                float y = 0;                switch (i % 4) {                    case 0:                    case 2:                        // 零点位于水位线上                        y = mLevelLine;                        break;                    case 1:                        // 往下波动的控制点                        y = mLevelLine + WAVE_HEIGHT;                        break;                    case 3:                        // 往上波动的控制点                        y = mLevelLine - WAVE_HEIGHT;                        break;                }                mPointsList.add(new PointF(x, y));            }        }    }    public void startMove() {        ValueAnimator moveValue = ValueAnimator.ofInt(0, mWaveWidth);        moveValue.setDuration(10000);        moveValue.setRepeatCount(-1);        moveValue.setRepeatMode(ValueAnimator.RESTART);        moveValue.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {            @Override            public void onAnimationUpdate(ValueAnimator animation) {                moveLen += speed;                if (Math.abs(moveLen) >= mWaveWidth - 1) {                    resetPoints();                }                movePoints();                invalidate();            }            private void movePoints() {                for (int i = 0; i < mPointsList.size(); i++) {                    mPointsList.get(i).x += speed;                }            }            private void resetPoints() {                moveLen = 0;                for (int i = 0; i < mPointsList.size(); i++) {                    mPointsList.get(i).x = (i * mWaveWidth / 4 - mWaveWidth);                }            }        });        moveValue.start();    }    public void setColor(int color) {        this.color = color;    }    public void setmWaveWidth(int mWaveWidth) {        this.mWaveWidth = mWaveWidth;    }    public void setSpeed(int speed) {        this.speed = speed;    }    public void setWAVE_HEIGHT(int WAVE_HEIGHT) {        this.WAVE_HEIGHT = WAVE_HEIGHT;    }}


2:更具需要添加不同数量的波进来,可以设置波速,振幅,波长,颜色

package test.vko.cn.ttapplication.weight;import android.content.Context;import android.graphics.Color;import android.util.AttributeSet;import android.widget.FrameLayout;import java.util.ArrayList;import java.util.List;/** * Created by JiaRH on 2015/11/23. */public class WaveMoveView extends FrameLayout {    private List<ShipWaveView> shipWaveViews;    private ShipWaveView swv0,swv1,swv2;    private ShipWaveViewSecond boatView;    public WaveMoveView(Context context) {        super(context);        init(context);    }    public WaveMoveView(Context context, AttributeSet attrs) {        super(context, attrs);        init(context);    }    public WaveMoveView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        init(context);    }    private void init(Context context) {        shipWaveViews = new ArrayList<>();        swv0 = new ShipWaveView(context);        swv1 = new ShipWaveView(context);        swv2 = new ShipWaveView(context);        boatView = new ShipWaveViewSecond(context);        swv0.setSpeed(3);        swv1.setSpeed(5);        swv2.setSpeed(7);        swv0.setColor(Color.parseColor("#8800a9ff"));        swv1.setColor(Color.parseColor("#8800a9ff"));        swv2.setColor(Color.parseColor("#10a1ea"));        swv0.setWAVE_HEIGHT(40);        swv1.setWAVE_HEIGHT(35);        swv2.setWAVE_HEIGHT(50);        swv0.setmWaveWidth(550);        swv1.setmWaveWidth(600);        swv2.setmWaveWidth(700);//        swv0.startBallAni();        shipWaveViews.add(swv0);        shipWaveViews.add(swv1);        shipWaveViews.add(swv2);       for(ShipWaveView swv : shipWaveViews){           this.addView(swv);           swv.startMove();       }        this.addView(boatView);    }}


3:绘制小船的路径

4:让小船动起来

package test.vko.cn.ttapplication.weight;import android.animation.ValueAnimator;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Path;import android.graphics.PathMeasure;import android.graphics.PointF;import android.util.AttributeSet;import android.view.View;import android.view.animation.LinearInterpolator;import java.util.ArrayList;import java.util.List;import test.vko.cn.ttapplication.R;/** * Created by JiaRH on 2015/11/19. */public class ShipWaveViewSecond extends View {    Paint mPaint;    private int color = Color.parseColor("#378DCC");    private int viewWidth;    private int viewHeight;    private final int WAVE_HEIGHT = 20;    private List<PointF> mPointsList;    private int mWaveWidth = 300;    private int mLevelLine;    private Path mWavePath;    private boolean isMeasured;    /**     * 记录当前运动点的位置     */    private float[] mCurrentPosition = new float[2];    private PathMeasure mPathMeature;    Bitmap boat;    ValueAnimator valueAnimator;    private int speed = 2;    private int moveLen = 0;    private float currentCircleX, currentCircleY;    private float radius = 5;    ValueAnimator circleValue;    public ShipWaveViewSecond(Context context) {        this(context, null);    }    public ShipWaveViewSecond(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public ShipWaveViewSecond(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        initData(context);        initPaint();        postDelayed(new Runnable() {            @Override            public void run() {                startBallAni();            }        }, 300);    }    private void initData(Context context) {        mPointsList = new ArrayList<>();        boat = BitmapFactory.decodeResource(getResources(), R.drawable.boat2);    }    private void initPaint() {        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);        mPaint.setStrokeWidth(1.5f);        mPaint.setStyle(Paint.Style.STROKE);        mWavePath = new Path();    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        mWavePath.reset();        mWavePath.moveTo(mPointsList.get(0).x, mPointsList.get(0).y);        for (int i = 0; i < mPointsList.size() - 2; i = i + 2) {            mWavePath.quadTo(mPointsList.get(i + 1).x,                    mPointsList.get(i + 1).y, mPointsList.get(i + 2)                            .x, mPointsList.get(i + 2).y);        }//        mWavePath.lineTo(viewWidth, 0);//        mWavePath.lineTo(0, 0);//        mWavePath.close();        mPathMeature = new PathMeasure(mWavePath, true);        drawPath(canvas);        drawBoat(canvas);    }    private void drawPath(Canvas canvas) {        mPaint.setColor(Color.TRANSPARENT);        // mPaint的Style是FILL,会填充整个Path区域        canvas.drawPath(mWavePath, mPaint);    }    private void drawBoat(Canvas canvas) {        mPaint.setColor(Color.BLUE);        if (mCurrentPosition[0] > viewWidth) {            mCurrentPosition[0] = viewWidth;            resetAni();        }        canvas.drawBitmap(boat, mCurrentPosition[0], mCurrentPosition[1], mPaint);    }    private void resetAni() {//        if (valueAnimator==null)return;        if (valueAnimator.isRunning()) {            valueAnimator.cancel();            startBallAni();        }    }    @Override    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {        super.onLayout(changed, left, top, right, bottom);        viewWidth = getWidth();        viewHeight = getHeight();        mLevelLine = viewHeight/2 - 110;        currentCircleX = (float) Math.floor(Math.random() * viewWidth);        currentCircleY = mLevelLine;        if (!isMeasured) {            isMeasured = true;            int n = (int) Math.round(viewWidth / mWaveWidth + 0.5);//            n=1;            // n个波形需要4n+1个点,            for (int i = 0; i < (4 * n)+5; i++) {                // 从P0开始初始化到P4n+4,总共4n+5个点//                float x = i * mWaveWidth / 4 - mWaveWidth;                float x = i * mWaveWidth / 4-boat.getWidth();                float y = 0;                switch (i % 4) {                    case 0:                    case 2:                        // 零点位于水位线上                        y = mLevelLine;                        break;                    case 1:                        // 往下波动的控制点                        y = mLevelLine + WAVE_HEIGHT;                        break;                    case 3:                        // 往上波动的控制点                        y = mLevelLine - WAVE_HEIGHT;                        break;                }                mPointsList.add(new PointF(x, y));                /**                 * 初始化小球的位置                 */                mCurrentPosition[0] = mPointsList.get(0).x;                mCurrentPosition[1] = mPointsList.get(0).y;            }        }    }    /**     * 开始小球的运动     */    private void startBallAni() {        if (mPathMeature==null)return;        valueAnimator = ValueAnimator.ofFloat(0, mPathMeature.getLength());        valueAnimator.setDuration(25000);        valueAnimator.setRepeatMode(ValueAnimator.RESTART);        valueAnimator.setRepeatCount(-1);        valueAnimator.setInterpolator(new LinearInterpolator());        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {            @Override            public void onAnimationUpdate(ValueAnimator animation) {                float value = (float) animation.getAnimatedValue();                mPathMeature.getPosTan(value, mCurrentPosition, null);                postInvalidate();            }        });        valueAnimator.start();    }}
5:使用方法:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical"    tools:context="test.vko.cn.ttapplication.activitys.ShipWaveActivity"><ImageView    android:id="@+id/bgg"    android:layout_alignParentTop="true"    android:layout_width="fill_parent"    android:layout_height="wrap_content"    android:scaleType="fitStart"    android:background="@drawable/bgg"/>    <test.vko.cn.ttapplication.weight.WaveMoveView        android:id="@+id/waveView"        android:layout_alignBottom="@+id/bgg"        android:layout_width="fill_parent"        android:layout_height="90dp" /></LinearLayout>



感谢如下文章及其作者:

参考文章:

http://blog.csdn.net/zhongkejingwang/article/details/38556891(分析的很NB)

http://blog.csdn.net/tianjian4592/article/details/44222565




0 0
原创粉丝点击