В этой статье я хочу поделиться одним из способов разработки
красивого анимированного меню или текстового горизонтального списка.
Идея
Для реализации такого списка я использую элемент TextSwitcher. Этот элемент
содержит в себе TextView,
который мы можем кастомизировать по своему усмотрению. TextSwitcher полезен для анимированной
смены текста.
Мы будем использовать 3 TextSwitcher. Основной Switcher используется для
идентификации текущего элемента в списке, а боковые – для возможности навигации
и для отображения ближайших элементов.
Для эффекта затенения мы создадим градиентный TextView с переходом от
прозрачного до нужного нам цвета.
Подготовка ресурсов
Для начала разработаем анимацию смены текста слева направо и
справа налево.
Исходный код anim/push_left_in.xml
<set xmlns:android="http://schemas.android.com/apk/res/android"
>
<translate
android:duration="300"
android:fromXDelta="-100%p"
android:toXDelta="0" />
<alpha
android:duration="300"
android:fromAlpha="0.0"
android:toAlpha="1.0"
/>
</set>
Исходный код anim/push_left_out.xml
<set xmlns:android="http://schemas.android.com/apk/res/android"
>
<translate
android:duration="300"
android:fromXDelta="0"
android:toXDelta="-100%p" />
<alpha
android:duration="300"
android:fromAlpha="1.0"
android:toAlpha="0.0"
/>
</set>
Исходный код anim/push_right_in.xml
<set xmlns:android="http://schemas.android.com/apk/res/android"
>
<translate
android:duration="300"
android:fromXDelta="100%p"
android:toXDelta="0" />
<alpha
android:duration="300"
android:fromAlpha="0.0"
android:toAlpha="1.0"
/>
</set>
Исходный код anim/push_right_out.xml
<set xmlns:android="http://schemas.android.com/apk/res/android"
>
<translate
android:duration="300"
android:fromXDelta="0"
android:toXDelta="100%p" />
<alpha
android:duration="300"
android:fromAlpha="1.0"
android:toAlpha="0.0"
/>
</set>
Для градиентного TextView необходимо описать его свойства:
Исходный код values/attrs.xml
<resources>
<declare-styleable name="GradientTextView">
<attr name="colorStartGradient"
format="integer" />
<attr name="colorEndGradient"
format="integer" />
</declare-styleable>
</resources>
Так же добавим цвета для градиента:
Исходный код values/colors.xml
<resources>
<color name="textview_start_gradient">#00ffffff</color>
<color name="textview_end_gradient">#88ffffff</color>
</resources>
Разработаем основной макет окна, который будет содержать
наше анимированное меню:
Исходный код layout/main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextSwitcher
android:id="@+id/scoreboard_location_left"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<TextSwitcher
android:id="@+id/scoreboard_location"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<TextSwitcher
android:id="@+id/scoreboard_location_right"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
</LinearLayout>
TextSwitcher
содержит в себе TextView.
В нашем проекте будут использоваться два вида текстовых элементов управления:
обычный (для центрального элемента) и градиентный (для боковых элементов).
Исходный код layout/central_textview.xml
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:id="@+id/textview"
/>
Исходный код layout/gradient_textview.xml
<org.snowpard.proects.twenty.GradientTextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/org.snowpard.proects.twenty"
android:id="@+id/textview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
app:colorEndGradient="@color/textview_end_gradient"
app:colorStartGradient="@color/textview_start_gradient" />
Разработка приложения
- Создание градиентного TextView
public class GradientTextView extends TextView { private int colorStartGradient, colorEndGradient; private boolean direction; private LinearGradient gradient; public GradientTextView(Context context, AttributeSet attrs) { super(context, attrs); TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.GradientTextView); colorStartGradient = a.getColor(R.styleable.GradientTextView_colorStartGradient, -2); colorEndGradient = a.getColor(R.styleable.GradientTextView_colorEndGradient, -2); direction = false; } public void setDirection(boolean direction) { this.direction = direction; } @Override protected void onDraw(Canvas canvas) { if (colorStartGradient != -2 && colorEndGradient != -2) { gradient = new LinearGradient(direction ? getWidth() : 0, 0, direction ? 0 : getWidth(), 0, colorStartGradient, colorEndGradient, TileMode.CLAMP); getPaint().setShader(gradient); } super.onDraw(canvas); } }
- Разработка основного класса MainActivity, работа с горизонтальным меню.
Добавим в класс константы, которые будут отвечать за
направления анимации.
public static final int DIRECTION_NONE = 0; public static final int DIRECTION_LEFT = 1; public static final int DIRECTION_RIGHT = 2; private int current_direction = DIRECTION_RIGHT;
Опишем элементы управления и анимацию, которые будем использовать для работы с меню:
private TextSwitcher switcher, switcher_left, switcher_right; private Animation in_left, in_right, out_left, out_right;
И добавим в атрибуты класса массив айтемов для горизонтального меню и индекс для идентификации текущего айтема:
private String[] locations = {"Item 1", "Item 2", "Item 3", "Item 4", "Item 5"}; private int current_index;
Разработаем методы для работы с горизонтальным меню:
- setAnimation: для установки нужной анимации для смены
текста
private void setAnimation(TextSwitcher switcher, Animation in, Animation out) { switcher.setInAnimation(in); switcher.setOutAnimation(out); }
- initSwitch: инициализация TextSwitcher
private void initSwitch(TextSwitcher switcher, final int place, Animation in, Animation out, final Context context) { switcher.setFactory(new ViewFactory() { @Override public View makeView() { TextView view = (TextView)LayoutInflater.from(context).inflate((place == 0) ? R.layout.central_textview: R.layout.gradient_textview, null).findViewById(R.id.textview); if (view instanceof GradientTextView) ((GradientTextView)view).setDirection(place != 1); return view; } }); setAnimation(switcher, in, out); }
- setSwitch: смена айтема в горизонтальном меню
private void setSwitch(int direction) { boolean isUpdate = false; if (direction == DIRECTION_LEFT && current_index > 0) { isUpdate = true; current_index--; } else if (direction == DIRECTION_RIGHT && current_index < locations.length - 1) { isUpdate = true; current_index++; } else if (direction == DIRECTION_NONE) isUpdate = true; if (isUpdate) { if (direction != current_direction && direction != DIRECTION_NONE) { current_direction = direction; if (current_direction == DIRECTION_RIGHT) { setAnimation(switcher_left, in_right, out_left); setAnimation(switcher, in_right, out_left); setAnimation(switcher_right, in_right, out_left); } else { setAnimation(switcher_left, in_left, out_right); setAnimation(switcher, in_left, out_right); setAnimation(switcher_right, in_left, out_right); } } if (current_index - 1 >= 0) switcher_left.setText(locations[current_index - 1]); else switcher_left.setText(""); switcher.setText(locations[current_index]); if (current_index + 1 <= locations.length - 1) switcher_right.setText(locations[current_index + 1]); else switcher_right.setText(""); } }
Теперь необходимо все инициализироваться в методе onCreate() нашего Activity:
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); in_left = AnimationUtils.loadAnimation(this, R.anim.push_left_in); in_right = AnimationUtils.loadAnimation(this, R.anim.push_right_in); out_right = AnimationUtils.loadAnimation(this, R.anim.push_right_out); out_left = AnimationUtils.loadAnimation(this, R.anim.push_left_out); switcher = (TextSwitcher) findViewById(R.id.scoreboard_location); switcher_left = (TextSwitcher) findViewById(R.id.scoreboard_location_left); switcher_right = (TextSwitcher) findViewById(R.id.scoreboard_location_right); initSwitch(switcher, 0, in_right, out_left, this); initSwitch(switcher_left, 1, in_right, out_left, this); initSwitch(switcher_right, 2, in_right, out_left, this); switcher_left.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { setSwitch(DIRECTION_LEFT); } }); switcher_right.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { setSwitch(DIRECTION_RIGHT); } }); setSwitch(DIRECTION_NONE); }
Ссылки
- Исходные коды данного проекта можно скачать отсюда: zip
Комментариев нет:
Отправить комментарий