English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Реализация эффекта "слюнявить" с помощью Android Custom View

Эта статья рассказывает о реализации пользовательского View с помощью анимации свойств для достижения таких эффектов

Идея реализации довольно проста:

  • Нарисовать полупрозрачный круг
  • Реализуем два типа анимаций: расширение при нажатии и свертывание при не нажатии
  • Используя способ многоthreading, объединяем два предыдущих шага

Сначала посмотрим на часть рисования полупрозрачного круга

public class ClickCircleView extends View {
 private Bitmap bitmap;
 private Paint paint;
 private Canvas canvas;
 private boolean isSpreadFlag = false;// Маркер выполнения выстрела
 public boolean isSpreadFlag() {
  return isSpreadFlag;
 }
 public void setIsSpreadFlag(boolean isSpreadFlag) {
  this.isSpreadFlag = isSpreadFlag;
 }
 public ClickCircleView(Context context, int width, int height, int screenWidth, int screenHeight) {
  super(context);
  bitmap = Bitmap.createBitmap(screenWidth, screenHeight, Bitmap.Config.ARGB_8888); // Установить ширину и высоту битмапа
  canvas = new Canvas();
  canvas.setBitmap(bitmap);
  paint = new Paint(Paint.DITHER_FLAG);
  paint.setAntiAlias(true);
  paint.setColor(Color.WHITE);
  paint.setStyle(Paint.Style.FILL);
  paint.setAlpha(50);
  canvas.drawCircle(screenWidth / 2, screenHeight / 2, width / 2 + 10, paint);
  invalidate();
 }
 @Override
 protected void onDraw(Canvas canvas) {
  canvas.drawBitmap(bitmap, 0, 0, null);
 }
}

можно увидеть, что соответствующие свойства установлены на карандаше, затем напрямую вызывается метод drawCircle() на холсте для рисования полупрозрачного круга, в конце вызывается метод invalidate() для обновления View
обязательно нужно переопределить метод родителя onDraw(),否则 пользовательский View не будет работать
мы установили флаг isSpreadFlag, который используется для обозначения того, завершена ли анимация расширения

затем мы реализуем два эффекта анимации

при нажатии анимация расширения

<set xmlns:android="http://schemas.android.com/apk/res/android">
 <objectAnimator
  android:duration="1000"
  android:propertyName="scaleY"
  android:valueFrom="1.0"
  android:valueTo="1.8"
  android:valueType="floatType" />
 <objectAnimator
  android:duration="1000"
  android:propertyName="scaleX"
  android:valueFrom="1.0"
  android:valueTo="1.8"
  android:valueType="floatType" />
</set>

очень просто, это изменение значения scale, увеличение до 1,8 раза

не нажимая, анимация расширения и восстановления

<set xmlns:android="http://schemas.android.com/apk/res/android"
 android:ordering="together">
 <objectAnimator
  android:duration="1000"
  android:propertyName="scaleX"
  android:valueFrom="1.0"
  android:valueTo="1.2"
  android:valueType="floatType" />
 <objectAnimator
  android:duration="1000"
  android:propertyName="scaleY"
  android:valueFrom="1.0"
  android:valueTo="1.2"
  android:valueType="floatType" />
 <objectAnimator
  android:duration="1000"
  android:propertyName="scaleX"
  android:startOffset="1000"
  android:valueFrom="1.2"
  android:valueTo="1.0"
  android:valueType="floatType" />
 <objectAnimator
  android:duration="1000"
  android:propertyName="scaleY"
  android:startOffset="1000"
  android:valueFrom="1.2"
  android:valueTo="1.0"
  android:valueType="floatType" />
</set>

Аналогично предыдущей анимации, параметр startOffset можно использовать для управления порядком выполнения анимации, например, в Android: startOffset = "1000" означает, что анимация с этого свойства будет выполняться с задержкой в 1 секунду

Затем используйте поток для выполнения анимации и логики

часть анимации при не нажатии

mXiuyixiuButton.post(new Runnable() {
   @Override
   public void run() {
    clickCircleView = new ClickCircleView(CustomView1.this, mXiuyixiuButton.getWidth())
      , mXiuyixiuButton.getHeight(), mXiuyixiuLayout.getMeasuredWidth(),
      mXiuyixiuLayout.getMeasuredHeight());
    clickCircleView.setVisibility(View.VISIBLE);
    mXiuyixiuLayout.addView(clickCircleView);
    mXiuyixiuLayout.postInvalidate();
    // загрузить анимацию
    final Animator anim = AnimatorInflater.loadAnimator(CustomView1.this,
      R.animator.circle_scale_animator);
    anim.addListener(new AnimatorListenerAdapter() {
     @Override
     public void onAnimationEnd(Animator animation) {
      if (anim != null) {
       anim.start(); // повторно выполнить анимацию
      }
     }
    });
    anim.setTarget(clickCircleView);
    anim.start();
   }
  });

После инициализации clickCircleView добавьте этот view в родительский макет, загрузите анимацию и установите повторение,最后使用 postInvalidate() для обновления view в под线程е

часть анимации при нажатии

mXiuyixiuButton.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    clickCircleView.setVisibility(View.GONE); // скрыть View, представляющий круг, предназначенный для анимации
    final ClickCircleView item = new ClickCircleView(CustomView1.this, mXiuyixiuButton.getWidth())
      , mXiuyixiuButton.getHeight(), mXiuyixiuLayout.getWidth(),
      mXiuyixiuLayout.getHeight());
    Animator spreadAnim = AnimatorInflater.loadAnimator(CustomView1.this,
      R.animator.circle_spread_animator);
    spreadAnim.addListener(new AnimatorListenerAdapter() {
     @Override
     public void onAnimationEnd(Animator animation) {
      item.setIsSpreadFlag(true); // Маркировать завершение анимации
     }
    });
    spreadAnim.setTarget(item);
    spreadAnim.start();
    clickCircleViewList.add(item);
    mXiuyixiuLayout.addView(item);
    mXiuyixiuLayout.invalidate();
    handler.post(circleViewRunnable);
   }
  });


Скрыть анимацию без кликов, после инициализации ClickCircleView добавить этот view в список и добавить в родительский макет, затем загрузить анимацию и добавить флаг isSpreadFlag в конце анимации, в конце вызвать метод invalidate() для обновления view и запустить поток

thread_part

private Runnable circleViewRunnable = new Runnable() {
  public void run() {
   for (int i = 0; i < clickCircleViewList.size(); i++) {
    if (clickCircleViewList.get(i).isSpreadFlag()) {
     mXiuyixiuLayout.removeView(clickCircleViewList.get(i));
     clickCircleViewList.remove(i);
     mXiuyixiuLayout.postInvalidate();
    }
   }
   if (clickCircleViewList.size() <= 0) {
    clickCircleView.setVisibility(View.VISIBLE);
   }
   handler.postDelayed(this, 100);
  }
 };

Пробегитесь по списку, удалите view с флагом isSpreadFlag из списка и родительского макета, обновите view, и в конце проверьте, если список пуст, покажите анимацию при нажатии

В конце не забудьте удалить поток в onDestroy()

@Override
 protected void onDestroy() {
  super.onDestroy();
  handler.removeCallbacks(circleViewRunnable);
 }

Реализация эффекта с использованием пользовательского вида и анимации свойств имеет высокую степень взаимосвязи, но по сравнению с полным использованием пользовательского вида, этот метод более плавный. Большая часть кода взята из блогов других людей, но если просто использовать его без анализа, это не станет вашей знанием. Поэтому и появился этот блог.

Ссылка: несколько методов реализации функции "дуться" в Android с помощью支付宝

Вот и все, что было в этой статье, надеюсь, это поможет вам в изучении. Надеюсь, вы также поддержите руководства по крику.

Заявление: содержимое этой статьи взято из Интернета, авторские права принадлежат соответствующему автору. Контент предоставлен пользователями Интернета, автоматически загружен и не был отредактирован вручную. Сайт не обладает правами собственности и не несет ответственности за это. Если вы обнаружите контент,涉嫌侵犯版权, пожалуйста, отправьте письмо по адресу: notice#oldtoolbag.com (во время отправки письма замените # на @), и предоставьте соответствующие доказательства. Если подтвердится, что контент нарушает права на интеллектуальную собственность, сайт немедленно удалят涉嫌侵权的内容。

Основной учебник
Вам может понравиться