利用Android中自帶的動畫效果來實現彈力伸縮式選單,預設情況下,選單項為隱藏狀態,當點選某一圖示,開啟選單項,則通過一系列動畫效果實現選單項的展示;當再次點選該圖示時,關閉選單項,則通過一系列動畫實現選單項的隱藏。效果圖如下:
工具/原料
利用Android設定動畫的同時,並使用插入器(interpolator)來實現彈力
OvershootInterpolator插入器,表示向前甩出一定值後再回到之前的位置
AnticipateOvershootInterpolator插入器,表示開始的時候向後,然後向前甩
方法/步驟
自定義相對佈局I114gBoxRelativeLayout類,原始碼如下:
/**
*
*/
package com.i114gbox.sdk.ui;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Animation;
import android.widget.RelativeLayout;
import com.i114gbox.sdk.animation.I114gBoxZoomAnimation;
import com.i114gbox.sdk.utils.I114gBoxLogUtils;
/**
* 自定義相對佈局
*
* @author [email protected]
*
*/
public class I114gBoxRelativeLayout extends RelativeLayout {
private static String TAG = "I114gBoxRelativeLayout";
private Animation mAnimation;// 動畫物件
public I114gBoxRelativeLayout(Context ctx) {
super(ctx);
}
public I114gBoxRelativeLayout(Context ctx, AttributeSet attrs) {
super(ctx, attrs);
}
public I114gBoxRelativeLayout(Context ctx, AttributeSet attrs, int defStyle) {
super(ctx, attrs, defStyle);
}
/** 開始指定的動畫 **/
@Override
public void startAnimation(Animation animation) {
I114gBoxLogUtils.d(TAG, "The startAnimation method execute.");
super.startAnimation(animation);
this.mAnimation = animation;
this.getRootView().postInvalidate();// 重新整理介面,不需要Handler,是工作者執行緒
// this.getRootView().invalidate();//重新整理介面,需要被主執行緒呼叫,需要Handler
}
/** 通知和目前有關的檢視動畫開始 **/
@Override
protected void onAnimationStart() {
I114gBoxLogUtils.d(TAG, "The onAnimationStart method execute.");
super.onAnimationStart();
if (this.mAnimation instanceof I114gBoxZoomAnimation) {
setVisibility(View.VISIBLE);
}
}
/** 通知和目前有關的檢視動畫結束 **/
@Override
protected void onAnimationEnd() {
I114gBoxLogUtils.d(TAG, "The onAnimationEnd method execute.");
super.onAnimationEnd();
if (this.mAnimation instanceof I114gBoxZoomAnimation) {
setVisibility(((I114gBoxZoomAnimation) mAnimation).mDirection != I114gBoxZoomAnimation.Direction.HIDE ? View.GONE
: View.VISIBLE);
}
}
}
自定義圖片按鈕控制元件I114gBoxImageButton類,原始碼如下:
/**
*
*/
package com.i114gbox.sdk.ui;
import com.i114gbox.sdk.animation.I114gBoxZoomAnimation;
import com.i114gbox.sdk.utils.I114gBoxLogUtils;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Animation;
import android.widget.ImageButton;
/**
* 自定義ImageButton
*
* @author [email protected]
*
*/
public class I114gBoxImageButton extends ImageButton {
private static String TAG = "I114gBoxImageButton";
private Animation mAnimation;// 動畫物件
public I114gBoxImageButton(Context ctx) {
super(ctx);
}
public I114gBoxImageButton(Context ctx, AttributeSet attrs) {
super(ctx, attrs);
}
public I114gBoxImageButton(Context ctx, AttributeSet attrs, int defStyle) {
super(ctx, attrs, defStyle);
}
@Override
public void startAnimation(Animation animation) {
I114gBoxLogUtils.d(TAG, "The startAnimation method execute.");
super.startAnimation(animation);
this.mAnimation = animation;
this.getRootView().postInvalidate();
}
@Override
protected void onAnimationStart() {
I114gBoxLogUtils.d(TAG, "The onAnimationStart method execute.");
super.onAnimationStart();
if (this.mAnimation instanceof I114gBoxZoomAnimation) {
setVisibility(View.VISIBLE);
}
}
@Override
protected void onAnimationEnd() {
I114gBoxLogUtils.d(TAG, "The onAnimationEnd method execute.");
super.onAnimationEnd();
if (this.mAnimation instanceof I114gBoxZoomAnimation) {
setVisibility(((I114gBoxZoomAnimation) mAnimation).mDirection != I114gBoxZoomAnimation.Direction.HIDE ? View.GONE
: View.VISIBLE);
}
}
}
include到主layout中的佈局檔案如下:
android:layout_height="match_parent"
android:orientation="vertical" >
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false" >
android:id="@id/rl_menus_wrapper"
android:layout_width="match_parent"
android:layout_height="120dip"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:clipChildren="false"
android:clipToPadding="false"
android:focusable="true" >
android:id="@+id/menu_photo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_marginBottom="100.0px"
android:layout_marginLeft="10dp"
android:background="@drawable/menu_tapjoy"
android:visibility="gone" />
android:id="@+id/menu_people"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_marginBottom="100.0px"
android:layout_marginLeft="55dp"
android:background="@drawable/menu_qq"
android:visibility="gone" />
android:id="@+id/menu_place"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_marginBottom="100.0px"
android:layout_marginLeft="100dp"
android:background="@drawable/menu_wechat"
android:visibility="gone" />
android:id="@+id/menu_music"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_marginBottom="100.0px"
android:layout_marginLeft="145dp"
android:background="@drawable/menu_sina_weibo"
android:visibility="gone" />
android:id="@+id/menu_thought"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_marginBottom="100.0px"
android:layout_marginLeft="190dp"
android:background="@drawable/menu_facebook"
android:visibility="gone" />
android:id="@+id/menu_sleep"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_marginBottom="100.0px"
android:layout_marginLeft="235dp"
android:background="@drawable/menu_alipay"
android:visibility="gone" />
android:id="@id/rl_menu_main_shrink"
android:layout_width="60dp"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:background="@drawable/main_center_button" >
android:id="@id/iv_menu_main_plus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:contentDescription="@string/menu"
android:src="@drawable/menu_icn_plus" />
實現選單項開啟時的動畫效果:
// 獲取選單新增檢視
imageViewPlus = findViewById(I114gBoxResourceUtils.getId(ctx,
"iv_menu_main_plus"));
// 獲取選單包裹檢視組,存放多個選單項
menusWrapper = (ViewGroup) findViewById(I114gBoxResourceUtils.getId(
ctx, "rl_menus_wrapper"));
// 獲取選單新增檢視的佈局
menuShrinkView = findViewById(I114gBoxResourceUtils.getId(ctx,
"rl_menu_main_shrink"));
// layoutMain = (RelativeLayout) findViewById(R.id.layout_content);
// 開啟選單時,順時針動畫
animRotateClockwise = AnimationUtils.loadAnimation(ctx,
I114gBoxResourceUtils.getAnimId(ctx, "menu_rotate_clockwise"));
// 關閉選單時,逆時針動畫
animRotateAntiClockwise = AnimationUtils.loadAnimation(ctx,
I114gBoxResourceUtils.getAnimId(ctx,
"menu_rotate_anticlockwise"));
// 新增監聽事件
menuShrinkView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
showLinearMenus();// 顯示選單項
}
});
for (int i = 0; i < menusWrapper.getChildCount(); i++) {
menusWrapper.getChildAt(i).setOnClickListener(
new SpringMenuLauncher(intentActivity[i]));
}
/**
* 顯示選單項
*/
private void showLinearMenus() {
int[] size = I114gBoxSystemManagerUtils.getScreenSize(ctx);// 獲取螢幕高度和寬度
if (!areMenusShowing) {// 當選單未開啟時
I114gBoxAnimation.startAnimations(this.menusWrapper,
Direction.SHOW, size);
this.imageViewPlus.startAnimation(this.animRotateClockwise);
} else {// 當選單已開啟時
I114gBoxAnimation.startAnimations(this.menusWrapper,
Direction.HIDE, size);
this.imageViewPlus.startAnimation(this.animRotateAntiClockwise);
}
areMenusShowing = !areMenusShowing;
}
private class I114gBoxMenuLauncher implements OnClickListener {
private final Class cls;
private int resource;
private I114gBoxMenuLauncher(Class c, int resource) {
this.cls = c;
this.resource = resource;
}
private I114gBoxMenuLauncher(Class c) {
this.cls = c;
}
public void onClick(View v) {
MainActivity.this.startOpenMenuAnimations(v);// 開啟選單項動畫
Intent intent = new Intent(ctx, cls);
ctx.startActivity(intent);
}
}
/** 開啟選單項動畫 **/
private void startOpenMenuAnimations(View view) {
areMenusShowing = true;
Animation inAnimation = new I114gBoxShrinkAnimationOut(300);
Animation outAnimation = new I114gBoxEnlargeAnimationOut(300);
inAnimation.setInterpolator(new AnticipateInterpolator(2.0F));
// inAnimation.setInterpolator(new CycleInterpolator(2.0F));
inAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationEnd(Animation animation) {
MainActivity.this.imageViewPlus.clearAnimation();
}
@Override
public void onAnimationRepeat(Animation animation) {
}
@Override
public void onAnimationStart(Animation animation) {
}
});
view.startAnimation(outAnimation);
}
順時針動畫定義:
xmlns:android=";
android:interpolator="@android:anim/linear_interpolator"
android:duration="200"
android:fromDegrees="0.0"
android:toDegrees="225.0"
android:pivotX="50.0%"
android:pivotY="50.0%"
android:fillAfter="true"
android:fillEnabled="true"/>
逆時針動畫定義:
xmlns:android=";
android:interpolator="@android:anim/linear_interpolator"
android:duration="200"
android:fromDegrees="225.0"
android:toDegrees="0.0"
android:pivotX="50.0%"
android:pivotY="50.0%"
android:fillAfter="true"
android:fillEnabled="true"/>
注意事項
需要定義順時針和逆時針動畫檔案
需要將動畫效果和插入器相結合