2011-03-20 11 views
15

मैं वर्तमान में ग्राफिक्स और पथ के साथ काम कर रहा हूं, और मैं सफलतापूर्वक जो कुछ भी चाहता हूं उसे प्रदर्शित कर सकता हूं।एंड्रॉइड ड्राइंग एक एनिमेटेड लाइन

लेकिन मेरे SurfaceView पर सीधे एक रेखा खींचने के बजाय, मैं इसे एनीमेशन में प्रगतिशील रूप से आकर्षित करना चाहता हूं।

मैंने अभी तक जो किया है वह पथ बनाना है और पथ के साथ क्रमिक रूप से निर्देशांक पुनर्प्राप्त करने के लिए पथमेज़र का उपयोग करना है। यहां मूल रूप से मैंने अभी तक किया है

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

कोई जवाब नहीं! पथ और एंड्रॉइड ग्राफिक्स पैकेज के साथ कभी भी काम नहीं किया? – Sasuke

+0

हे sasuke एम एक ही समस्या के साथ अटक गया, क्या आपको कोई समाधान मिला ??? – dharan

उत्तर

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

अरे अद्भुत पोस्ट के लिए धन्यवाद। वह असली मेरी मदद करो। लेकिन अभी भी एक समस्या यह है कि पथ सरणी को कैसे परिभाषित किया जाए। मैं हल करने के लिए अपनी पूरी कोशिश करता हूं लेकिन मैं नहीं कर सकता। क्या आप मदद कर सकते हैं कृपया...! –

8

, प्रत्येक बार आपके वर्ग के तरीकों में से एक को कालबैक में 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(); 

इसके अलावा इस सवाल here, और this उदाहरण है, जो मैं पर मेरे कोड आधारित किया है देखते हैं।

+0

हे! आपका कोड मेरे लिए बहुत अच्छा काम करता है। हालांकि मैं अपने उपयोग के मामले में एक अतिरिक्त चाहता हूं। मुझे वर्तमान पथ की शुरुआत और अंत में सर्किलों को आकर्षित करने की आवश्यकता है, व्यास चौड़ाई के साथ व्यास के साथ, जिसका अर्थ है स्ट्रोक कैप काम नहीं करेगा। प्रारंभ सर्कल अपनी स्थिति पर रहता है लेकिन पथ के साथ अंत सर्कल चलता है। मेरे पास प्रारंभिक निर्देशांक हैं इसलिए मैं canvas.drawCircle को कॉल कर सकता हूं। लेकिन मैं यह नहीं समझ सकता कि मैं सर्कल को आकर्षित करने के लिए पथ के वर्तमान छोर के निर्देशांक कैसे प्राप्त करूं। मेरे लिए कोई विचार है? – gitter

+0

@skunkwerk, इस उत्तर के लिए धन्यवाद। जब मैंने गतिविधि से इनिट को कॉल करने का प्रयास किया, तो ऐप क्रैश हो गया क्योंकि यह कहता है कि पथ ड्रॉ में शून्य है। साथ ही, मैं इस जवाब में एनीमेशन श्रोता कैसे सेट करूं? – Rakesh

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

+0

आपको इस दृश्य को लेआउट में जोड़ना होगा, ऊंचाई को 1 तक सेट करना होगा और पैरेंट से मिलान करने के लिए चौड़ाई को जोड़ना होगा। रेखा बाएं से दाएं एनिमेटेड होगी। बाद की रेखा को पहले स्थान पर रखा जाएगा। –

संबंधित मुद्दे