Ответ 1
Мы должны перенести это в поля ответа.
OP в основном получил его здесь, и фактически обновленный OP gist блистателен.
Некоторые общие советы относительно первой попытки в вопросе:
1) В protected void onSizeChanged(int w, int h, int oldw, int oldh)
:
-
width = w;
нет причин, по которым вы не можете позвонитьgetWidth()
, когда это потребуется. Причина, по которой это целесообразно, состоит в том, что внутренняя ширинаView
устанавливается довольно поздно послеonMeasure
. Следовательно,onDraw
может быть в следующий раз, когда вы захотите получить самую последнюю версию, поэтому используйте getter там. -
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
. Создание растрового изображения - это дорогостоящая операция с интенсивной памятью. Если вы не хотите писать растровое изображение в файл или отправить его вBitmapDrawable
дляImageView
или что-то еще, вам не нужно это делать. Особенно с эффектами, нарисованными на пользовательском интерфейсе с помощью библиотеки androidgraphics
. -
mCanvas = new Canvas(mBitmap);
, за которым следует операция рисования на новом холсте. Это никогда не нужно. И все же я видел это (не работает) во многих кодовых базах и попытках. Я думаю, что это ошибка старой записи, которая заставила людей делать это, чтобы они могли трансформировать холст на пользовательский вид, не делая рисунок на остальной части холста. Кстати, если вам это нужно, используйте.restore()
и.save()
. Если вы видитеnew Canvas
, быть подозрительным.
2) onDraw(...)
:
- Да, вам нужно избегать действий в
onDraw
, например, создания объектов или любой тяжелой обработки. Но вам все равно нужно делать вещи вonDraw
, которые вам нужно сделать вonDraw
! - Итак, здесь вам просто нужно вызвать:
canvas.drawCircle(float cx, float cy, float radius, Paint paint)
с аргументами в соответствии с документами. - Это действительно не грех для
onDraw
. Если вы беспокоитесь о том, чтобы называть это слишком много, как может быть, если вся ваша кнопка анимации по экрану, вам нужно использовать аппаратное ускорение, доступное в более позднем интерфейсе API версии, как будет описано в статье под названием Оптимизация представления; очень полезное чтение, если вы используете множество пользовательских обращений.
3) Этот надоедливый радиальный градиент. Следующий вопрос, который у вас был, - это то, что вы правильно создали свою краску в методе init
, чтобы создание объекта не было выполнено. Но тогда, вполне справедливо, у вас будет IllegalArgumentException
ed (я думаю), потому что на этом этапе getHeight()
для представления было 0. Вы пытались передать небольшие значения пикселей - это не сработает, если вы не узнаете какую-либо магию о размеры экрана.
Это не ваша проблема, как раздражающий цикл просмотра в основе дизайна Android. Исправить хотя и достаточно просто: просто используйте более позднюю часть процесса рисования вида после вызова onMeasure
, чтобы установить фильтр краски.
Но есть некоторые проблемы с получением этого права, а именно, что иногда, досадно, onDraw
вызывается до того момента, когда вы ожидаете его. В результате ваша краска будет нулевой, и вы не получите желаемого поведения.
Я нашел более надежное решение - просто сделать нахальную и озорную маленькую нулевую проверку в onDraw
, а затем только построить там объект рисования. Это не строго говоря, оптимально, но с учетом сложного способа, с помощью которого объекты Paint
соединяются с родным слоем на основе Android, лучше, чем пытаться расположить конфигурацию и конструкцию краски во многих часто называемых местах. И это делает для более четкого кода.
Это будет выглядеть (внося изменения в суть):
@Override
protected void onDraw(final Canvas canvas) {
super.onDraw(canvas);
if (mPaint == null) {
mPaint = new Paint();
mPaint.setColor(Color.BLACK);
mPaint.setStrokeWidth(1);
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setShader(new RadialGradient(getWidth() / 2, getHeight() / 2,
getHeight() / 3, Color.TRANSPARENT, Color.BLACK, TileMode.MIRROR));
}
width = getWidth();
height = getHeight();
canvas.drawCircle(width / 2, height / 2, height / 3, mPaint);
}
Итак, обратите внимание на несколько изменений - я думаю, что из вашего описания вы хотите, чтобы два цвета обменивались аргументами, также не забывайте центрировать центр вашего градиента в вашем представлении: аргументы width/2
и height/2
.
Удачи!