原文鏈接: https://yalantis.com/blog/how-we-used-micro-transitions-for-smooth-android-to-do-list-animations/
譯者: Eirture
列表(Lists)在各種應用中都是重要的控件,包括時間管理、購物和健身等各種應用。
To-do list作為一個獨自的類別,經常能在意志(motivation)類應用中找到它,它幫助人們管理時間,避免拖延癥,提高效率。To-do list 的工作模式是去提醒人們完成排滿的日程。
在Yalantis近期的一個項目,我們有一個小任務,是創(chuàng)建一個 To-do list ,挑戰(zhàn)在于我們要做的與眾不同并且能給用戶帶來樂趣,目的是我們需要一些工具,使管理任務列表變得快速和直觀。
我們想讓用戶感覺與他們在屏幕上交互的,就好像是生活中真實立體的物品一樣。
使用微變換(microtransitions),能讓一個對象平滑的過渡到另一個對象。
微變換的使用再一次證明,使用一些小的動畫會有畫龍點睛的效果,讓看似簡介的設計更有新鮮感,也會帶來更真實的體驗。
在定下這個設計理念后,我們與工程師一起來實現它。
我們不得不把動畫拆成可以單獨工作的幾個部分:“加”的動畫、“光標”的動畫、添加列表項的動畫,以及列表項的移動動畫。
如何實現“加”按鈕的動畫
在屏幕上實現從“加號”變成“光標”的小動畫對開發(fā)部分來說是一個挑戰(zhàn)。我們在控件中使用 ViewPropertyAnimationCompat 類來實現所有的動畫,使用 ‘rotation()’ 方法來旋轉視圖
public void rotate(@Nullable Runnable endAction) {
AnimationUtil.rotate(mHorizontalView, 180, endAction);
}
public static void rotate(View view, int value, @Nullable Runnable endAction) {
ViewPropertyAnimatorCompat animator = ViewCompat.animate(view).rotation(value);
if (endAction != null) {
animator.withEndAction(endAction);
}
animator.setDuration(Constant.ANIM_DURATION_MILLIS).start();
}
光標動畫
有挑戰(zhàn)的部分是,在相同的位置上,讓“加號”變換成輸入框內部的光標。
Android EditText 控件默認的光標不能達到這個目的,因為它不容易控制。因此我們用一個自定義的光標來實現它。我們自定義了一個BarEditText控件:包含了默認的 EditText 和在它上面的作為光標的視圖。
當用戶輸入時,如何移動光標的位置
RxTextView.textChanges(mEditText).subscribe(new Action1<CharSequence>() {
@Override
public void call(CharSequence charSequence) {
if (!TextUtils.isEmpty(charSequence)) {
moveCursor();
} else {
moveToStart();
}
}
});
private void moveCursor() {
mCursor.setX(getCursorPosition() + mCursor.getWidth() * 1.5f);
mCursor.setY(mEditText.getY());
}
private float getCursorPosition() {
Layout layout = mEditText.getLayout();
if (layout == null) {
return 0;
}
int position = mEditText.getSelectionStart();
return layout.getPrimaryHorizontal(position);
}
public void moveToStart() {
mCursor.setX(mEditText.getX());
mCursor.setY(mEditText.getY());
}
我們使用了 RxBinding 來接收用戶在輸入框內改變文本的事件。
因此可以通過 'call()' 方法的參數拿到編輯的文本。如何文本存在,通過 'getCursorPosition()' 方法來計算自定義光標的位置,然后改變自定義光標的X、Y值來改變光標位置。
如何實現列表添加條目的動畫
當用戶輸入文字并且點擊‘添加’按鈕時,輸入框應當平滑的向下移動,變成 to-do 列表的首項。我們創(chuàng)建一個自定義視圖來實現這個動畫,其中包含了 RecyclerView 和一個頂部的視圖,這個頂部視圖像首部一樣,其中包含了帶光標 (BarEditText) 的自定義 EditText 。因此,當用戶點擊"添加"時,這個首部視圖移動到 RecyclerView 的首項位置的上方,與此同時,添加一個新的條目,但是在首部移動期間它是不可見的。完成之后,再讓列表首項可見,并且開始執(zhí)行首部入場動畫。
如何實現列表項動畫
為了實現列表項動畫,我們不得不創(chuàng)建一個自定義列表項動畫,將移動動畫分成了幾個重要的步驟:
- 升起當前點擊的列表項
- 移動到指定的位置
- 放下它
每一步都要一步接一步,因此我們使用** ‘withEndAction()’** 方法來等待上一部分的動畫完成,再去執(zhí)行下一個動畫。
private void animateMoveImpl(final BatAdapter.ViewHolder holder) {
final View view = holder.itemView;
//needed to increase checked item only, not all moved items
//僅升起需要的列表項,不是所有
final boolean isMainView = isMainListItem(holder.getItemPosition());
//increasing checked item. 升起被點擊的列表項
ViewCompat.animate(view).scaleX(isMainView ? 1.05f : 1).scaleY(isMainView ? 1.05f : 1)
.setDuration(mAnimationType == AnimationType.MOVE ? Constant.ANIM_DURATION_MILLIS : 0)
.withEndAction(new Runnable() {
@Override
public void run() {
//moving item to needed position. 移動到需要的位置
ViewCompat.animate(view).translationX(0).translationY(0).setDuration(Constant.ANIM_DURATION_MILLIS)
.withEndAction(new Runnable() {
@Override
public void run() {
if (isMainListItem(holder.getItemPosition())) {
//descreasing checked item. 放下被點擊的列表項
ViewCompat.animate(view).scaleX(1).scaleY(1).start();
mPosition = -1;
}
}
});
我們需要用 ‘isMainView’ 字段來存儲用戶點擊列表項的位置。用于幫助我們區(qū)分被點擊的和普通的列表項。如果不用 ‘isMainView’,所有的列表項都會被提升起來。
精心設計的 to-do list 可以提升用戶體驗,即使在一個簡潔的產品也應該添加一個優(yōu)秀的交互。不要猶豫,吸取我們的經驗,應用在你自己的 to-do list 上。
查看我們 To-Do List 的動畫: