Intereting Posts
Обнаружение ориентации панели навигации Android Получение запроса POST на сервере (Spring Framework) из приложения Android Пробейте отверстие в наложении прямоугольника с ускорением HW, включенным в представлении Как центрировать выравнивание заголовка ActionBar в Android? Получить координаты касания относительно вида (эквивалент ScreenToClient?) Декомпиляция DEX в исходный код Java Использование google-аккаунта для входа в Android-приложение Android Studio E / dalvikvm: Не удалось найти класс '.DatabaseHelper', на который ссылается метод .DatabaseManager Обновлено до версии SDK 2.3 – теперь эмуляторы не имеют возможности подключения Исключить HTML-теги и некоторые символы UNICODE во время поиска в SQLite Разрешение проблемы Google Play Java, android, разрешить URL-адрес, получить перенаправленный uri Программно введите секретный код, например * # * # 4636 # * # * на Android Android: приложение с сообщением о сбое Как записывать экран и делать скриншоты, используя Android API?

Android-анимированная линия

В настоящее время я работаю с графикой и дорожками, и я могу успешно отображать все, что захочу.

Но вместо того, чтобы рисовать строку непосредственно на моем SurfaceView, я бы хотел сделать это постепенно в анимации.

То, что я сделал до сих пор, – это создать Путь, а затем использовать 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; } 

Вопросительные знаки – это то место, где я застрял. Я хочу последовательно рисовать путь и видеть его анимированным на экране. Я не мог найти много информации об этом в Интернете, поэтому любая подсказка была бы очень признательна, если бы вы столкнулись с той же ситуацией. Окончательный эффект, который я хочу создать, похож на карандаш, рисующий постепенно текст автоматически.

Solutions Collecting From Web of "Android-анимированная линия"

Я просто решаю эту проблему, вот что я делаю:

 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); } } } 

Этот пример – это адаптация того, что я сделал (чтобы упростить пример). Надеюсь, вы это поймете. Поскольку я только что запустил эту функцию, ей не хватает оптимизаций и тому подобного.

Надеюсь, это поможет 😉

Вместо создания цикла 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(); 

Также см. Этот вопрос здесь , и этот пример, на который я основал мой код.

Вам нужно будет добавить это представление в макет, установив высоту в 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" /> 

Вот альтернативное решение, которое сработало для меня

  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(); } });