MainActivity.java
public class MainActivity extends AppCompatActivity { private ArcDemo mArc; private ListView mListView; private List<String> mData; private ArrayAdapter mAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mArc = (ArcDemo) findViewById(R.id.view_arc); mArc.setOnSubItemClickListener(new ArcDemo.onSubItemClickListener() { @Override public void onItemClick(View view, int position) { Toast.makeText(MainActivity.this, "position" + position, Toast.LENGTH_SHORT).show(); } }); initListView(); } private void initListView() { mListView = (ListView) findViewById(R.id.listview); mData = new ArrayList<String>(); for (int i = 'A'; i <= 'z'; i++) { mData.add((char) i + ""); } mAdapter = new ArrayAdapter<String>( MainActivity.this, android.R.layout.simple_list_item_1, mData); mListView.setAdapter(mAdapter); mListView.setOnScrollListener(new AbsListView.OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { if (mArc.isOpen()) { mArc.subItemAnim(); } } }); } }
ArcDemo.java
public class ArcDemo extends ViewGroup { private View mButton; private BStatus mBStatus = BStatus.STATUS_CLOSE; private onSubItemClickListener onListener; public enum BStatus { STATUS_OPEN, STATUS_CLOSE } //子菜单点击接口 public interface onSubItemClickListener { void onItemClick(View view, int position); } public void setOnSubItemClickListener(onSubItemClickListener mListener) { this.onListener = mListener; } public ArcDemo(Context context) { super(context); // this(context, null); } public ArcDemo(Context context, AttributeSet attrs) { super(context, attrs); // this(context, attrs, 0); } public ArcDemo(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int count = getChildCount(); for (int i = 0; i < count; i++) { measureChild(getChildAt(i), widthMeasureSpec, heightMeasureSpec); } super.onMeasure(widthMeasureSpec, heightMeasureSpec); } //添加布局,就是所要显示的控件View @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { if (changed) { //主菜单按钮 onMainButton(); //子菜单按钮 onSubItemButton(); } } //获取主菜单按钮 private void onMainButton() { mButton = getChildAt(0); mButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { //主菜单动画 Animation rotateAnim = AnimationUtils.loadAnimation(getContext(), R.anim.anim); mButton.startAnimation(rotateAnim); //子菜单动画 subItemAnim(); } }); int l, t, r = 0, b = 0; int mWidth = mButton.getMeasuredWidth(); int mHeight = mButton.getMeasuredHeight(); l = getMeasuredWidth() - mWidth; t = getMeasuredHeight() - mHeight; mButton.layout(l, t, getMeasuredWidth(), getMeasuredHeight()); } //获取子菜单按钮 private void onSubItemButton() { int count = getChildCount(); for (int i = 0; i < count - 1; i++) { View childView = getChildAt(i + 1); //开始时不呈现子菜单 childView.setVisibility(View.GONE); int radius = 350; int cl, ct, cr, cb; cr = (int) (radius * Math.sin(Math.PI / 2 / (count - 2) * i)); cb = (int) (radius * Math.cos(Math.PI / 2 / (count - 2) * i)); int cWidth = childView.getMeasuredWidth(); int cHeight = childView.getMeasuredHeight(); cl = getMeasuredWidth() - cWidth - cr; ct = getMeasuredHeight() - cHeight - cb; //layout(l,t,r,b);前两参数决定位置,后两参数决定大小 //参数(1,t)为View控件的左上角坐标 // (r-l,b-t)为View控件大小,r-l为控件宽度,b-t为控件高度 childView.layout(cl, ct, getMeasuredWidth() - cr, getMeasuredHeight() - cb); } } //子菜单散开回笼动画 public void subItemAnim() { int count = getChildCount(); for (int i = 0; i < count - 1; i++) { final View cView = getChildAt(i + 1); //点击主菜单后,子菜单就立刻呈现,否则后面的动画无法完成 cView.setVisibility(VISIBLE); int radius = 350; int l, t, r, d; r = (int) (radius * Math.sin(Math.PI / 2 / (count - 2) * i)); d = (int) (radius * Math.cos(Math.PI / 2 / (count - 2) * i)); // int cWidth = cView.getMeasuredWidth(); // int cHeight = cView.getMeasuredHeight(); // // l = getMeasuredWidth() - cWidth - r; // t = getMeasuredHeight() - cHeight - d; AnimationSet set = new AnimationSet(true); Animation tranAnim = null; if (mBStatus == BStatus.STATUS_CLOSE) { //散开动画 tranAnim = new TranslateAnimation(r, 0, d, 0); cView.setClickable(true); cView.setFocusable(true); } else { //回笼动画 tranAnim = new TranslateAnimation(0, r, 0, d); cView.setClickable(false); cView.setFocusable(false); } tranAnim.setDuration(300); // tranAnim.setFillAfter(true); //让最后一帧的动画不消失 tranAnim.setStartOffset(100 * i / count); tranAnim.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { if (mBStatus == BStatus.STATUS_CLOSE) { cView.setVisibility(GONE); } } @Override public void onAnimationRepeat(Animation animation) { } }); Animation rotateAnim = new RotateAnimation( 0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); rotateAnim.setDuration(300); // rotateAnim.setFillAfter(false); set.addAnimation(rotateAnim); set.addAnimation(tranAnim); cView.startAnimation(set); //散开后子菜单的点击监听事件 final int pos = i + 1; cView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (onListener != null) { onListener.onItemClick(cView, pos); } //散开后点击子菜单动画 subItemClickAnim(pos - 1); changStatus(); } }); } changStatus(); } //监听子菜单状态改变 private void changStatus() { mBStatus = (mBStatus == BStatus.STATUS_CLOSE ? BStatus.STATUS_OPEN : BStatus.STATUS_CLOSE); } //散开后点击子菜单动画 private void subItemClickAnim(int pos) { int count = getChildCount(); for (int i = 0;i<count-1;i++) { View cView = getChildAt(i+1); if(i == pos) { //变大,变透明 cView.startAnimation(toBig()); } else { //变小,变透明 cView.startAnimation(toSmall()); } cView.setClickable(false); cView.setFocusable(false); } } //变大,变透明 private Animation toBig(){ Animation big = AnimationUtils.loadAnimation(getContext(), R.anim.bigalpha); return big; } //变小,变透明 private Animation toSmall(){ Animation small = AnimationUtils.loadAnimation(getContext(),R.anim.smallalpha); return small; } //给ListView调用 public boolean isOpen() { return mBStatus == BStatus.STATUS_OPEN; } }
activity_main.xml
<RelativeLayout 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" tools:context=".MainActivity"> <ListView android:id="@+id/listview" android:layout_width="match_parent" android:layout_height="match_parent"/> <my.com.example.x550v.view.ArcDemo android:id="@+id/view_arc" android:layout_width="match_parent" android:layout_height="match_parent"> <RelativeLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/composer_button"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:src="@drawable/composer_icn_plus" /> </RelativeLayout> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/composer_camera" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/composer_with" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/composer_thought" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/composer_music" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/composer_place" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/composer_sleep" /> </my.com.example.x550v.view.ArcDemo> </RelativeLayout>
anim.xml
<set xmlns:android="http://schemas.android.com/apk/res/android"> <rotate android:duration="300" android:fromDegrees="0" android:toDegrees="360" android:pivotX="50%" android:pivotY="50%"/> </set>
bigalpha.xml
<!--android:fillAfter="true"得加,取动画结束后的最后一帧--> <set xmlns:android="http://schemas.android.com/apk/res/android" android:fillAfter="true"> <alpha android:duration="200" android:fromAlpha="1" android:toAlpha="0"/> <scale android:duration="200" android:fromXScale="1" android:fromYScale="1" android:toXScale="3" android:toYScale="3" android:pivotX="50%" android:pivotY="50%" /> </set>
smallalpha.xml
<!--android:fillAfter="true"得加,取动画结束后的最后一帧--> <set xmlns:android="http://schemas.android.com/apk/res/android" android:fillAfter="true"> <alpha android:duration="200" android:fromAlpha="1" android:toAlpha="0"/> <scale android:duration="200" android:fromXScale="1" android:fromYScale="1" android:toXScale="0" android:toYScale="0" android:pivotX="50%" android:pivotY="50%" /> </set>
运行效果: