Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
517 views
in Technique[技术] by (71.8m points)

android - Weird flickering with DashPathEffect animation

I'm trying to make a path animation with DashPathEffect. Have to be able to replay it multiple times, using a button.

Based on http://www.curious-creature.org/2013/12/21/android-recipe-4-path-tracing/

My problem is, the animation works well the first 10 times or so, then the path goes crazy and it starts flickering, going in the reverse order or finishes where it doesn't have to.

I logged the values of the animation and the values passed to the path and they look correct, no jumps or anything weird. I have no idea what is causing the issues.

This is the code:

public class Test extends View {

    private float mDrag;

    private MyPath path1;

    private int mDuration;

    //just some shape
    private static Path makeDragPath(int radius) {
        Path p = new Path();
        RectF oval = new RectF(10.0f, 10.0f, radius * 2.0f, radius * 2.0f);

        float cx = oval.centerX();
        float cy = oval.centerY();
        float rx = oval.width() / 2.0f;
        float ry = oval.height() / 2.0f;

        final float TAN_PI_OVER_8 = 0.414213562f;
        final float ROOT_2_OVER_2 = 0.707106781f;

        float sx = rx * TAN_PI_OVER_8;
        float sy = ry * TAN_PI_OVER_8;
        float mx = rx * ROOT_2_OVER_2;
        float my = ry * ROOT_2_OVER_2;

        float L = oval.left;
        float T = oval.top;
        float R = oval.right;
        float B = oval.bottom;

        p.moveTo(R, cy);
        p.quadTo(      R, cy + sy, cx + mx, cy + my);
        p.quadTo(cx + sx, B, cx, B);
        p.quadTo(cx - sx,       B, cx - mx, cy + my);
        p.quadTo(L, cy + sy, L, cy);
        p.quadTo(      L, cy - sy, cx - mx, cy - my);
        p.quadTo(cx - sx, T, cx, T);


        return p;
    }




    public Test(Context context, AttributeSet attrs) {
        super(context, attrs);

        init();
    }




    public static class MyPath {
        private static final Region sRegion = new Region();
        private static final Region sMaxClip = new Region(
                Integer.MIN_VALUE, Integer.MIN_VALUE,
                Integer.MAX_VALUE, Integer.MAX_VALUE);

        final Path path;
        final Paint paint;
        final float length;
        final Rect bounds;

        MyPath(Path path, Paint paint) {
            this.path = path;
            this.paint = paint;

            PathMeasure measure = new PathMeasure(path, false);
            this.length = measure.getLength();

            sRegion.setPath(path, sMaxClip);
            bounds = sRegion.getBounds();
        }


    }


    private static PathEffect createPathEffect2(float pathLength, float phase) {

        //I modified the original approach using phase, to use only path instead because later I want to animate also the starting point and phase alone is not enough for this

        float full = phase * pathLength;

        return new DashPathEffect(new float[] {full, Float.MAX_VALUE}, //on, off
                0);
    }

    ObjectAnimator current;


    public void startAnim() {
        if (current != null) {
            current.cancel();
        }

        current = ObjectAnimator.ofFloat(Test.this, "drag", 0.0f, 1.0f).setDuration(mDuration);
        current.start();
    }

    private void scalePath(Path path, float scale) {
        Matrix scaleMatrix = new Matrix();
        scaleMatrix.setScale(scale, scale);
        path.transform(scaleMatrix);
    }

    private void init() {

        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setStyle(Paint.Style.STROKE);

        paint.setStrokeWidth(8.0f);
        paint.setColor(0xffffffff);

        mDuration = 3000;

        Path p1 = makeDragPath(40);
        scalePath(p1, 3);

        path1 = new MyPath(p1, paint);


        startAnim();
    }

    public float getDrag() {
        return mDrag;
    }

    public void setDrag(float drag) {

        mDrag = drag;

        path1.paint.setPathEffect(createPathEffect2(path1.length, mDrag));

        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.drawColor(Color.BLACK); //doesn't help

        canvas.drawPath(path1.path, path1.paint);
    }

}

In my activity:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_my);

    final Test test = (Test)findViewById(R.id.test);

    Button button = (Button)findViewById(R.id.startTest);
    button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            test.startAnim();
        }
    });
}

xml:

<Button
    android:id="@+id/startTest"
    android:layout_width="200dp"
    android:layout_alignParentBottom="true"
    android:layout_alignParentLeft="true"
    android:layout_height="60dp" />

<com.example.ivanschuetzd.myapplication.Test
    android:id="@+id/test"
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:layout_alignParentBottom="true"
    android:layout_alignParentRight="true"
    android:background="#000000"
    />

Any idea? Or maybe a different approach to make this kind of animation with an arbitrary path? Thanks!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Just found a solution for that. Apparently the problem is the hardware acceleration that is somewhat buggy with the DashPathEffect. Just call

setLayerType(View.LAYER_TYPE_SOFTWARE, null);

in your view and that should fix it.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...