Освой Android играючи
/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000
<rotate> (XML)
Метроном
Аттракцион
Бутылочка
Используйте атрибуты fromDegrees и toDegrees внутри тега <rotate>, чтобы задать начальный и конечный углы поворота вокруг опорной точки. Опорная точка указывается с помощью атрибутов pivotX и pivotY, которые содержат процентные значения относительно ширины и высоты объекта Drawable соответственно.
Рассмотрим примеры вращения объекта. Создадим проект, в котором ImageView будет постоянно вращаться либо относительно своего центра, либо вокруг своего угла. В папке res/anim создаем два файла:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/linear_interpolator" >
<rotate
android:duration="2000"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:startOffset="0"
android:toDegrees="360" />
</set>
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/linear_interpolator" >
<rotate
android:duration="2000"
android:fromDegrees="0"
android:pivotX="0%"
android:pivotY="0%"
android:startOffset="0"
android:toDegrees="360" />
</set>
Разместим на форме две кнопки и ImageView:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="@+id/rotatecenter"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Вращение относительно центра" />
<Button
android:id="@+id/rotatecorner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Вращение относительно угла картинки" />
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="120dp"
android:src="@drawable/ic_launcher" />
</LinearLayout>
Теперь код для анимации:
package ru.alexanderklimov.rotate;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.AnimationUtils;
import android.widget.Button;
import android.widget.ImageView;
public class MainAppActivity extends Activity {
ImageView myImageView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
myImageView = findViewById(R.id.imageView);
Button buttonRotateCenter = findViewById(R.id.rotatecenter);
Button buttonRotateCorner = findViewById(R.id.rotatecorner);
final Animation animationRotateCenter = AnimationUtils.loadAnimation(
this, R.anim.rotate_center);
final Animation animationRotateCorner = AnimationUtils.loadAnimation(
this, R.anim.rotate_corner);
buttonRotateCenter.setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick(View view) {
myImageView.startAnimation(animationRotateCenter);
}
});
buttonRotateCorner.setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick(View view) {
myImageView.startAnimation(animationRotateCorner);
}
});
}
}
Запускайте проект и вращайте картинку.
Класс RotateAnimation наследуется от класса Animation и отвечает за анимацию вращения.
Добавим на экран ImageButton, который будет объектом вращения.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
<ImageButton
android:id="@+id/imagebutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onClick"
android:layout_gravity="center_vertical|center_horizontal"
android:src="@drawable/pinkhellokitty" />
</LinearLayout>
Напишем обработчик щелчка кнопки:
public void onClick(View view) {
RotateAnimation animation = new RotateAnimation(-30, 60, 100, 180);
animation.setRepeatMode(Animation.REVERSE);
animation.setRepeatCount(Animation.INFINITE);
animation.setInterpolator(new LinearInterpolator());
animation.setDuration(1000L);
view.startAnimation(animation);
}
Числа для вращения я подбирал наугад, можете использовать свои значения, зависящие от размеров экрана и т.п. В данном примере движение картинки напоминает работу метронома.
Следующая анимация напомнила мне аттракцион в парке развлечений. За основу взять пример из урока, где мы учились выводить текст вдоль окружности.
package ru.alexanderklimov.rotateanimation;
import ...
public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new GraphicsView(this));
}
static public class GraphicsView extends View {
private RotateAnimation animation;
public GraphicsView(Context context) {
super(context);
}
@Override
protected void onDraw(Canvas canvas) {
// creates the animation the first time
if (animation == null) {
createAnimation(canvas);
}
// Настраиваем окружность
Paint cPaint = new Paint();
cPaint.setColor(Color.BLUE); // цвет круга
cPaint.setStyle(Style.STROKE); // делаем окантовку вместо круга
cPaint.setStrokeWidth(2.0f); // толщина окантовки
cPaint.setAntiAlias(true); // сглаживание
// Работаем с текстом
Paint tPaint = new Paint();
tPaint.setTextSize(36); // размер текста
tPaint.setAntiAlias(true); // сглаживание
tPaint.setColor(Color.BLUE); // цвет текста
Path circle = new Path();
circle.addCircle(240, 240, 115, Direction.CW);
canvas.drawPath(circle, cPaint);
canvas.drawTextOnPath("Коты и кошки всех стран, соединяйтесь! * ",
circle, 0, 32, tPaint);
}
private void createAnimation(Canvas canvas) {
animation = new RotateAnimation(0, 360, canvas.getWidth() / 2, canvas.getHeight() / 2);
animation.setRepeatMode(Animation.REVERSE);
animation.setRepeatCount(Animation.INFINITE);
animation.setDuration(10000L);
animation.setInterpolator(new AccelerateDecelerateInterpolator());
startAnimation(rotate);
}
}
}
Если нужно, чтобы был эффект вращения текста внутри окружности, то следует поколдовать с координатами, например, у меня вышло так:
protected void onDraw(Canvas canvas) {
// creates the animation the first time
if (rotate == null) {
createAnimation(canvas);
}
// Настраиваем окружность
Paint cPaint = new Paint();
cPaint.setColor(Color.BLUE); // цвет круга
cPaint.setStyle(Style.STROKE); // делаем окантовку вместо круга
cPaint.setStrokeWidth(2.0f); // толщина окантовки
cPaint.setAntiAlias(true); // сглаживание
// Работаем с текстом
Paint tPaint = new Paint();
tPaint.setTextSize(36); // размер текста
tPaint.setAntiAlias(true); // сглаживание
tPaint.setColor(Color.BLUE); // цвет текста
Path circle = new Path();
int centerX = canvas.getWidth() / 2;
int centerY = canvas.getHeight() / 2;
circle.addCircle(centerX, centerY, 115, Direction.CW);
canvas.drawPath(circle, cPaint);
canvas.drawTextOnPath("Коты и кошки всех стран, соединяйтесь! * ",
circle, 0, 32, tPaint);
}
Можно написать даже простую игру "Бутылочка". Понадобится изображение бутылки с молоком, которую потом отдадим котёнку.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/imageview_bottle"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_centerInParent="true"
app:srcCompat="@drawable/bottle"/>
</RelativeLayout>
При нажатии на бутылку запускается вращение.
package ru.alexanderklimov.rotation;
import ...
public class MainActivity extends AppCompatActivity {
public static final Random sRandom = new Random();
private ImageView mBottleImageView;
private int lastAngle = -1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBottleImageView = (ImageView) findViewById(R.id.imageview_bottle);
mBottleImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
spinBottle();
}
});
}
private void spinBottle() {
int angle = sRandom.nextInt(3600 - 360) + 360;
// Центр вращения
float pivotX = mBottleImageView.getWidth() / 2;
float pivotY = mBottleImageView.getHeight() / 2;
final Animation animation = new RotateAnimation(lastAngle == -1 ? 0 : lastAngle, angle, pivotX, pivotY);
lastAngle = angle;
animation.setDuration(2500);
animation.setFillAfter(true);
mBottleImageView.startAnimation(animation);
}
// В примере не используется
private void resetBottle() {
float pivotX = mBottleImageView.getWidth() / 2;
float pivotY = mBottleImageView.getHeight() / 2;
final Animation animation = new RotateAnimation(lastAngle == -1 ? 0 : lastAngle, 0, pivotX, pivotY);
lastAngle = -1;
animation.setDuration(2000);
animation.setFillAfter(true);
mBottleImageView.startAnimation(animation);
}
}
Не забыли про мою просьбу отдать бутылку котёнку?
Крутить можно не только бутылку, но и спиннер. На скорую руку написал приложение.
Картинку рисовал в векторе, а также прикрутил к веб-странице.