2011-03-20 139 views
15

我目前正在使用圖形和路徑,我可以成功地顯示任何我想要的。安卓繪製動畫線

但不是直接在我的SurfaceView上繪製直線,我想在動畫中逐漸繪製它。

到目前爲止我所做的是創建一個Path,然後使用PathMeasure逐步檢索路徑上的座標。這裏基本上是我迄今爲止所做的

PathMeasure pm = new PathMeasure(myPath, false); 

    float position = 0; 
    float end = pm.getLength(); 
    float[] coord = {0,0,0,0,0,0,0,0,0}; 

    while (position < end){ 
     Matrix m = new Matrix(); 
     // put the current path position coordinates into the matrix 
     pm.getMatrix(position, m, PathMeasure.POSITION_MATRIX_FLAG | PathMeasure.TANGENT_MATRIX_FLAG); 
     // put the matrix data into the coord array (coord[2] = x and coord[5] = y) 
     m.getValues(coord); 
     ???? 
     position += 1; 

    } 

問號是我被卡住的地方。我想逐步繪製路徑並在屏幕上看到它的動畫。我在網上找不到關於它的很多信息,所以如果你已經遇到過相同的情況,任何線索都會非常感激。我想創建的最終效果就像鉛筆逐漸自動地繪製文本。

+0

沒有答案!沒有人曾經使用過Path和android圖形包? – Sasuke 2011-03-23 08:22:30

+0

嘿sasuke米卡住了同樣的問題,你找到任何解決方案? – dharan 2011-08-09 09:37:00

回答

5

我必須解決這個問題,在這裏我做什麼:

private float[] mIntervals = { 0f, 0f }; 
private float drawSpeed = 2f; 
private int currentPath = -1; 
private PathMeasure mPathMeasure = new PathMeasure(); 
private ArrayList<Path> mListPath = new ArrayList<Path>(this.pathCount); 


@Override 
protected void onDraw(Canvas canvas) { 
    if (mIntervals[1] <= 0f && currentPath < (pathCount - 1)) { 
    // Set the current path to draw 
    // getPath(int num) a function to return a path. 
    Path newPath = this.getPath(mListPath.size()); 
    this.mListPath.add(newPath); 
    this.mPathMeasure.setPath(newPath, false); 
    mIntervals[0] = 0; 
    mIntervals[1] = this.mPathMeasure.getLength(); 
    } 

    if (mIntervals[1] > 0) { 
    // draw the previous path 
    int last = this.mListPath.size(); 
    for (int i = 0; i < last; i++) { 
     canvas.drawPath(this.mListPath.get(i), mPaint); 
    } 
    // partially draw the last path 
    this.mPaint.setPathEffect(new DashPathEffect(mIntervals, 0f)); 

    canvas.drawPath(this.mListPath.get(last), mPaint); 

    // Update the path effects values, to draw a little more 
    // on the path. 
    mIntervals[0] += drawSpeed; 
    mIntervals[1] -= drawSpeed; 

    super.invalidate(); 
    } else { 
    // The drawing have been done, draw it entirely 
    for (int i = 0; i < this.mListPath.size(); i++) { 
     canvas.drawPath(this.mListPath.get(i), mPaint); 
    } 
    } 
} 

這個例子,是我做了什麼(簡化的例子)的適應。希望你能理解它。由於我剛剛使這個功能起作用,它缺乏優化和類似的東西。

希望這將有助於;-)

+1

嘿感謝精彩的帖子。真正幫助我。但還有一個問題是如何定義Path數組。我盡我所能解決,但我不能。你能幫忙嗎...! – 2012-07-24 07:26:39

8

而是for循環創建的,你可以使用ObjectAnimator類回調到每一次的類的方法之一,你想吸引更多一點的路徑。

import android.animation.ObjectAnimator; 
import android.content.Context; 
import android.graphics.Canvas; 
import android.graphics.Color; 
import android.graphics.DashPathEffect; 
import android.graphics.Paint; 
import android.graphics.Path; 
import android.graphics.PathEffect; 
import android.graphics.PathMeasure; 
import android.util.AttributeSet; 
import android.view.View; 
import android.util.Log; 

public class PathView extends View 
{ 
    Path path; 
    Paint paint; 
    float length; 

    public PathView(Context context) 
    { 
     super(context); 
    } 

    public PathView(Context context, AttributeSet attrs) 
    { 
     super(context, attrs); 
    } 

    public PathView(Context context, AttributeSet attrs, int defStyleAttr) 
    { 
     super(context, attrs, defStyleAttr); 
    } 

    public void init() 
    { 
     paint = new Paint(); 
     paint.setColor(Color.BLUE); 
     paint.setStrokeWidth(10); 
     paint.setStyle(Paint.Style.STROKE); 

     path = new Path(); 
     path.moveTo(50, 50); 
     path.lineTo(50, 500); 
     path.lineTo(200, 500); 
     path.lineTo(200, 300); 
     path.lineTo(350, 300); 

     // Measure the path 
     PathMeasure measure = new PathMeasure(path, false); 
     length = measure.getLength(); 

     float[] intervals = new float[]{length, length}; 

     ObjectAnimator animator = ObjectAnimator.ofFloat(PathView.this, "phase", 1.0f, 0.0f); 
     animator.setDuration(3000); 
     animator.start(); 
    } 

    //is called by animtor object 
    public void setPhase(float phase) 
    { 
     Log.d("pathview","setPhase called with:" + String.valueOf(phase)); 
     paint.setPathEffect(createPathEffect(length, phase, 0.0f)); 
     invalidate();//will calll onDraw 
    } 

    private static PathEffect createPathEffect(float pathLength, float phase, float offset) 
    { 
     return new DashPathEffect(new float[] { pathLength, pathLength }, 
      Math.max(phase * pathLength, offset)); 
    } 

    @Override 
    public void onDraw(Canvas c) 
    { 
     super.onDraw(c); 
     c.drawPath(path, paint); 
    } 
} 

然後,只需調用的init()開始動畫,像這樣(或者,如果你希望它儘快視圖充氣開始,把在init()構造函數調用內):

PathView path_view = (PathView) root_view.findViewById(R.id.path); 
path_view.init(); 

也看到了這個問題herethis例如,我已經基於我的代碼。

+0

嘿!你的代碼對我很好。儘管如此,我還需要一個額外的用例。我需要在當前路徑的開始和結束處繪製圓,其直徑大於筆畫寬度,這意味着筆畫帽不起作用。開始圈保持在其位置,但結束圈沿着路徑移動。我有起始座標,所以我可以調用canvas.drawCircle。但我無法弄清楚如何獲得當前路徑末端的座標來繪製圓。對我有什麼想法? – gitter 2016-04-18 10:03:58

+0

@skunkwerk,謝謝你的回答。當我嘗試從Activity調用init時,該應用程序崩潰,因爲它在onDraw中表示path爲null。另外,我將如何設置動畫聽衆在這個答案? – Rakesh 2017-05-20 11:15:47

0

這裏是一個替代的解決方案,對我來說

package com.sample; 
/** 
* Created by Sumit 
*/ 
public class PathView extends View { 

Paint mPaint; 
Path mPath; 
int mStrokeColor; 
float mStrokeWidth; 

float mProgress = 0.0f; 
float mLength = 0f; 
float mTotal; 

public PathView(Context context) { 
    this(context, null); 
    init(); 
} 

public PathView(Context context, AttributeSet attrs) { 
    this(context, attrs, 0); 
    init(); 
} 

public PathView(Context context, AttributeSet attrs, int defStyle) { 
    super(context, attrs, defStyle); 

    mStrokeColor = Color.RED; 
    mStrokeWidth = 8.0f; 
    init(); 
} 

private void init() { 
    mPaint = new Paint(); 
    mPaint.setColor(mStrokeColor); 
    mPaint.setStyle(Paint.Style.STROKE); 
    mPaint.setStrokeWidth(mStrokeWidth); 
    mPaint.setStrokeCap(Paint.Cap.ROUND); 
    mPaint.setAntiAlias(true); 
    mPaint.setDither(true); 

    setPath(new Path()); 
    // setPath2(new Path()); 
} 

public void setPath(Path p) { 
    mPath = p; 
    PathMeasure measure = new PathMeasure(mPath, false); 
    mPathLength = measure.getLength(); 
} 


public void setPath(List<float[][]> list) { 
    Log.d("Path", "size " + list.size()); 
    Path p = new Path(); 
    p.moveTo(list.get(0)[0][0], list.get(1)[0][1]); 

    for (int i = 1; i < list.size(); i++) { 
     p.lineTo(list.get(i)[0][0], list.get(i)[0][1]); 
     //if (i > 100) 
      //p.moveTo(list.get(i)[0][0], list.get(i)[0][1]); 
    } 
    //p.setFillType(FillType.WINDING); 
    setPath(p); 
} 

@Override 
protected void onDraw(Canvas canvas) { 
    super.onDraw(canvas); 
    mTotal = (mLength - mLength * mProgress); 
    PathEffect pathEffect = new DashPathEffect(new float[] { mLength, mLength }, mTotal); 
    Log.d("Path Tag", "length =" + mLength + ", totla=" + mTotal); 

    mPaint.setPathEffect(pathEffect); 

    canvas.save(); 
    // canvas.translate(getPaddingLeft(), getPaddingTop()); 
    canvas.drawPath(mPath, mPaint); 
    canvas.restore(); 
} 

@Override 
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
    super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
    int widthSize = MeasureSpec.getSize(widthMeasureSpec); 
    int heightSize = MeasureSpec.getSize(heightMeasureSpec); 
    int widthMode = MeasureSpec.getMode(widthMeasureSpec); 
    int heightMode = MeasureSpec.getMode(widthMeasureSpec); 

    int measuredWidth, measuredHeight; 

    if (widthMode == MeasureSpec.AT_MOST) 
     throw new IllegalStateException("Use MATCH_PARENT"); 
    else 
     measuredWidth = widthSize; 

    if (heightMode == MeasureSpec.AT_MOST) 
     throw new IllegalStateException("Use MATCH_PARENT"); 
    else 
     measuredHeight = heightSize; 

    setMeasuredDimension(measuredWidth, measuredHeight); 
    setPath(); 
} 

void setPath() { 
    int cX = getWidth()/2; 
    int cY = getHeight()/2; 
    cY += 50; 
    cX -= 50; 
    List<float[][]> list = new ArrayList<float[][]>(); 

    for (int i = 0; i < 50; i++) { 
     list.add(new float[][] { { cX--, cY++ } }); 
    } 

    for (int i = 0; i < 100; i++) { 
     list.add(new float[][] { { cX--, cY-- } }); 
    } 

    for (int i = 0; i < 100; i++) { 
     list.add(new float[][] { { cX++, cY-- } }); 
    } 

    for (int i = 0; i < 200; i++) { 
     list.add(new float[][] { { cX++, cY++ } }); 
    } 

    for (int i = 0; i < 100; i++) { 
     list.add(new float[][] { { cX++, cY-- } }); 
    } 
    for (int i = 0; i < 100; i++) { 
     list.add(new float[][] { { cX--, cY-- } }); 
    } 

    for (int i = 0; i < 100; i++) { 
     list.add(new float[][] { { cX--, cY++ } }); 
    } 

    setPath(list); 
} 

}工作

,並使用

final PathView pathView = (PathView) findViewById(R.id.path_view); 
pathView.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View view) { 
      ObjectAnimator anim = ObjectAnimator.ofFloat(view, "percentage", 0.0f, 1.0f); 
      anim.setDuration(2000); 
      anim.setInterpolator(new LinearInterpolator()); 
      anim.setRepeatCount(Animation.INFINITE); 
      anim.start(); 
     } 
    }); 
1

你將不得不這種觀點添加到佈局,設置高度爲1,寬度以匹配父項。該行將從左到右進行動畫。後面的一行將放在第一行。

   public class AnimatorLineView extends RelativeLayout { 

        private View animatorLineView; 
        private View simpleLineView; 
        View animatorLine; 
        private int colorBeforeAnimation; 
        private int colorAfterAnimation; 
        private int colorForErrorLine; 

        public AnimatorLineView(Context context) { 
         super(context); 
         init(); 
         startAnimation(); 
        } 

        public AnimatorLineView(Context context, AttributeSet attrs) { 
         super(context, attrs); 
         init(); 
         initAttributes(context, attrs); 
         setColors(); 
         startAnimation(); 
        } 

        public AnimatorLineView(Context context, AttributeSet attrs, int defStyleAttr) { 
         super(context, attrs, defStyleAttr); 
         init(); 
         initAttributes(context, attrs); 
         setColors(); 
         startAnimation(); 
        } 


        private void setColors() { 
         simpleLineView.setBackgroundColor(colorBeforeAnimation); 
         animatorLine.setBackgroundColor(colorAfterAnimation); 
        } 

        public void init() { 
         animatorLineView = inflate(getContext(), R.layout.ainimator_line_view, this); 
         animatorLine = findViewById(R.id.simple_line); 
         simpleLineView = findViewById(R.id.animator_line); 

        } 

        public void setColor(int color) { 
         animatorLine.setBackgroundColor(color); 
        } 

        public void startAnimation() { 
         animatorLine.setVisibility(View.VISIBLE); 
         Animation animation = AnimationUtils.loadAnimation(getContext(), R.anim.enter_animation_underline); 
         animatorLine.startAnimation(animation); 
        } 

        public void showErrorLine(){ 
         animatorLine.setBackgroundColor(colorForErrorLine); 
         animatorLine.setVisibility(View.VISIBLE); 
         Animation animation = AnimationUtils.loadAnimation(getContext(), R.anim.enter_animation_underline); 
         animatorLine.startAnimation(animation); 
        } 

        public void hideErrorLine(){ 
         animatorLine.setBackgroundColor(colorAfterAnimation); 
         animatorLine.setVisibility(View.VISIBLE); 
         Animation animation = AnimationUtils.loadAnimation(getContext(), R.anim.enter_animation_underline); 
         animatorLine.startAnimation(animation); 
        } 

        private void initAttributes(Context context, AttributeSet attributeSet) { 
         TypedArray attr = getTypedArray(context, attributeSet, R.styleable.ProgressButton); 
         if (attr == null) { 
          return; 
         } 
         try { 
          colorBeforeAnimation = attr.getColor(R.styleable.AnimatorLineView_al_color_after_animation,ContextCompat.getColor(getContext(), R.color.animation_line_text_color)); 
          colorAfterAnimation = attr.getColor(R.styleable.ProgressButton_pb_text_color, ContextCompat.getColor(getContext(), R.color.black_color)); 
          colorForErrorLine = attr.getColor(R.styleable.ProgressButton_pb_text_color, ContextCompat.getColor(getContext(), R.color.error_msgs_text_color)); 
         } finally { 
          attr.recycle(); 
         } 
        } 

        protected TypedArray getTypedArray(Context context, AttributeSet attributeSet, int[] attr) { 
         return context.obtainStyledAttributes(attributeSet, attr, 0, 0); 
        } 

        public void resetColor(){ 
         animatorLine.setBackgroundColor(colorAfterAnimation); 
         animatorLine.setVisibility(View.GONE); 
        } 
       } 

      <animator_line_view> 

      <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
       android:layout_width="match_parent" 
       android:layout_height="wrap_content" 
       android:orientation="horizontal"> 

       <View 
        android:id="@+id/simple_line" 
        android:layout_width="match_parent" 
        android:layout_height="1.5dp" 
        android:background="#E0E0E0" /> 

       <View 
        android:id="@+id/animator_line" 
        android:layout_width="match_parent" 
        android:layout_height="1.5dp" 
        android:background="#000000" 
        android:visibility="gone" /> 

      </FrameLayout> 

     <enter_animation_underline> 

     <?xml version="1.0" encoding="utf-8"?> 
     <set xmlns:android="http://schemas.android.com/apk/res/android" 
      android:shareInterpolator="false"> 
      <translate 
       android:fromXDelta="-100%" android:toXDelta="0%" 
       android:fromYDelta="0%" android:toYDelta="0%" 
       android:duration="@integer/animator_line_duration" /> 
     </set> 
    ---- styles------ 
     <style name="animator_line"> 
      <item name="android:layout_width">match_parent</item> 
      <item name="android:layout_height">wrap_content</item> 
      <item name="al_color_before_animation">#E0E0E0</item> 
      <item name="al_color_after_animation">#0000000</item> 
      <item name="al_error_line_color">#FF3352</item> 
     </style> 

     <declare-styleable name="AnimatorLineView"> 
      <attr name="al_color_before_animation" format="color" /> 
      <attr name="al_color_after_animation" format="color" /> 
      <attr name="al_error_line_color" format="color" /> 
     </declare-styleable> 

-------- to be include in the xml 
<com.careem.acma.widget.AnimatorLineView 
     android:id="@+id/animator_line" 
     style="@style/animator_line" /> 
+0

你可以加一點解釋這是什麼嗎? – Ares 2017-07-21 13:04:49

+0

您必須將此視圖添加到佈局,將高度設置爲1並將寬度設置爲與父級匹配。該行將從左到右進行動畫。後面的一行將放在第一行。 – 2017-07-21 14:04:41