Уроки, алгоритмы, программы, примеры

Вход на сайт

Материалы по разделам

Построения
на плоскости (2D)
Графика
в пространстве (3D)
Вычислительная
геометрия
Физическое
моделирование
Фрактальная
графика

Новые комментарии

Всем у кого не работает. файл wizard.script Ещё одно упоминание Glut32 в строке "if (!VerifyLibFile(dir_nomacro_lib, _T("glut32"), _T("GLUT's"))) return false;" меняем на "if (!VerifyLibFile(dir_nomacro_lib, _T("freeglut"), _T("GLUT's"))) return...
Не получается, емаё
огромное спасибо за подробное объяснение про 3д графику на питоне, в интернете очень мало подобной информации
dobryj den, popytalas otkryt prikreplionnyj fail ctoby posmotret kak rabotaet, no mne ego ne pokazyvaet vydajet osibku. Pochemu?
Очень интересно! ии сайт крутой жалко что умирает(

Счетчики и рейтинг

Рейтинг@Mail.ru Яндекс.Метрика
Среда программирования: 
Android Studio

В уроке Анимация на Android я показал, как делать анимацию с помощью View и функции invalidate(). Но у такого метода есть недостаток - метод invalidate() вызывает onDraw() не мгновенно, а когда решит операционная система. И если анимация требует тяжелых расчетов, она может заметно тормозить.
Для тяжелых случаев есть другой метод рисования через SurfaceView.

Класс SurfaceView предоставляет объект Surface, который поддерживает рисование в фоновом потоке и дает возможность использовать OpenGL для трехмерной графики. Это отличный вариант для насыщенных графикой элементов, которые нуждаются в частых обновлениях или должны отображать сложную графическую информацию, как в случае с играми и трехмерной визуализацией.

Основной плюс SurfaceView в том, что он работает в паре с объектом класса Thread, что позволяет выполнять тяжелые графические расчеты в отдельном потоке.

Создадим в нашем проекте еще два класса: MySurfaceView и MyThread.

MySurfaceView:

package me.graphica.canvasanimation;
 
import android.content.Context;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
 
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback {
 
    private MyThread mMyThread; //наш поток прорисовки
 
    public MySurfaceView(Context context) {
        super(context);
        getHolder().addCallback(this);
    }
 
    @Override
    public void surfaceCreated(SurfaceHolder holder) { //вызывается, когда surfaceView появляется на экране
        mMyThread = new MyThread(getHolder());
        mMyThread.setRunning(true);
        mMyThread.start(); //запускает процесс в отдельном потоке
    }
 
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        //когда view меняет свой размер
    }
 
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) { //когда view исчезает из поля зрения
        boolean retry = true;
        mMyThread.setRunning(false); //останавливает процесс
 
        while(retry) {
            try {
                mMyThread.join(); //ждет окончательной остановки процесса
                retry = false;
            }
            catch (InterruptedException e) {
                //не более чем формальность
            }
        }
    }
}

MyThread:

package me.graphica.canvasanimation;
 
import android.animation.ArgbEvaluator;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.Log;
import android.view.SurfaceHolder;
 
/**
 * Created by Sex_predator on 27.03.2016.
 */
public class MyThread extends Thread {
 
    private final int REDRAW_TIME    = 10; //частота обновления экрана - 10 мс
    private final int ANIMATION_TIME = 1_500; //анимация - 1,5 сек
 
    private final SurfaceHolder mSurfaceHolder; //нужен, для получения canvas
 
    private boolean mRunning; //запущен ли процесс
    private long    mStartTime; //время начала анимации
    private long    mPrevRedrawTime; //предыдущее время перерисовки
 
    private Paint mPaint;
    private ArgbEvaluator mArgbEvaluator;
 
    public MyThread(SurfaceHolder holder) {
        mSurfaceHolder = holder;
        mRunning = false;
 
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.FILL);
 
        mArgbEvaluator = new ArgbEvaluator();
    }
 
    public void setRunning(boolean running) { //запускает и останавливает процесс
        mRunning = running;
        mPrevRedrawTime = getTime();
    }
 
    public long getTime() {
        return System.nanoTime() / 1_000_000;
    }
 
    @Override
    public void run() {
        Canvas canvas;
        mStartTime = getTime();
 
        while (mRunning) {
            long curTime = getTime();
            long elapsedTime = curTime - mPrevRedrawTime;
            if (elapsedTime < REDRAW_TIME) //проверяет, прошло ли 10 мс
                continue;
//если прошло, перерисовываем картинку
            canvas = null;
            try {
                canvas = mSurfaceHolder.lockCanvas(); //получаем canvas
                synchronized (mSurfaceHolder) {
                    draw(canvas); //функция рисования
                }
            }
            catch (NullPointerException e) {/*если canvas не доступен*/}
            finally {
                if (canvas != null)
                    mSurfaceHolder.unlockCanvasAndPost(canvas); //освобождаем canvas
            }
 
            mPrevRedrawTime = curTime;
        }
    }
 
    private void draw(Canvas canvas) {
        long curTime = getTime() - mStartTime;
 
        int width = canvas.getWidth();
        int height = canvas.getHeight();
 
        canvas.drawColor(Color.BLACK);
 
        int centerX = width / 2;
        int centerY = height / 2;
 
        float maxSize = Math.min(width, height) / 2;
 
        float fraction = (float) (curTime % ANIMATION_TIME) / ANIMATION_TIME;
 
        int color = (int) mArgbEvaluator.evaluate(fraction, Color.RED, Color.BLACK);
        mPaint.setColor(color);
 
        canvas.drawCircle(centerX, centerY, maxSize * fraction, mPaint);
    }
}

Не рекомендуется делать REDRAW_TIME слишком маленьким, это может сильно нагружать систему. 10 мс вполне достаточно.

Последний штрих: вернемся в MyActivity и сменим
setContentView(new MyView(this));
на
setContentView(new MySurfaceView(this));

Приложение должно выглядеть так: