序:在网上看到别人写的什么arcmenu菜单,就是卫星菜单,第一眼看到感觉很酷,我对UI方面的东西不是特别的在乎,只要不是太丑陋就行。这里为练手 我也来比划一下,
山寨一个卫星菜单。先看看效果吧:
下面是实现:实现的逻辑都写在代码的注释里了,总体实现逻辑:
1:计算出每个item的位置
2:添加动画效果
3:处理开关控制逻辑
首先是布局文件:一个FrameLayout布局
<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">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="android studio 动画"
android:layout_marginTop="20dp"
android:onClick="btnclick"
android:id="@+id/btn"
/>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/btn">
<TextView android:text="item1"
android:id="@+id/item1"
android:textSize="25sp"
android:layout_margin="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<TextView android:text="item2"
android:id="@+id/item2"
android:textSize="25sp"
android:layout_margin="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<TextView android:text="关闭"
android:id="@+id/item3"
android:textSize="25sp"
android:layout_margin="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<TextView android:text="item4"
android:id="@+id/item4"
android:textSize="25sp"
android:layout_margin="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<TextView android:text="item5"
android:id="@+id/item5"
android:textSize="25sp"
android:layout_margin="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<!--android:background="@android:drawable/btn_radio"-->
<RadioButton
android:id="@+id/radio"
android:textSize="25sp"
android:layout_margin="10dp"
android:button="@null"
android:layout_width="64dp"
android:layout_height="64dp"
android:background="@drawable/menu"
/>
</FrameLayout>
</RelativeLayout>
然后是在activity中 初始化控件,并左相应的逻辑处理:
package com.example.administrator.applicationname;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.TimeInterpolator;
import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.PointF;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.animation.BaseInterpolator;
import android.view.animation.BounceInterpolator;
import android.view.animation.CycleInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.widget.Button;
import android.widget.RadioButton;
import android.widget.TextView;
import android.widget.Toast;
import org.w3c.dom.Text;
import java.lang.reflect.Array;
import java.text.Format;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.IllegalFormatCodePointException;
import java.util.MissingFormatArgumentException;
import java.util.concurrent.ThreadLocalRandom;
public class MainActivity extends Activity implements View.OnClickListener {
//菜单按钮
RadioButton radio;
Button btn;
//负责存放菜单条目,这里用textview表示。
ArrayList<TextView> items = new ArrayList<TextView>();
//负责记录动画:把动画加入到集合中表示动画开启 了。当关闭动画时清空掉。
ArrayList<ObjectAnimator> animators = new ArrayList<ObjectAnimator>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = (Button) findViewById(R.id.btn);
radio = (RadioButton) findViewById(R.id.radio);
TextView item1 = (TextView) findViewById(R.id.item1);
TextView item2 = (TextView) findViewById(R.id.item2);
TextView item3_close = (TextView) findViewById(R.id.item3);
TextView item4 = (TextView) findViewById(R.id.item4);
TextView item5 = (TextView) findViewById(R.id.item5);
item3_close.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (radio.isChecked()) {
closeAnimator();
radio.setChecked(false);
}
}
});
items.add(item1);
items.add(item2);
items.add(item3_close);
items.add(item4);
items.add(item5);
radio.setOnClickListener(this);
radio.setChecked(false);
}
/**
* 关闭动画这里用reverse,也可以记录动画的轨迹参数来反执行一下。
*/
public void closeAnimator(){
for (ObjectAnimator animator : animators) {
animator.reverse();
}
//清楚记录的动画
animators.clear();
}
@Override
public void onClick(View v) {
//集合里有数据表示动画已经开启,重复点击 不响应。
if(animators.size()>0){
closeAnimator();
return;
}
if(items.size()<3){
Toast.makeText(this, "最少三个item", Toast.LENGTH_SHORT).show();
}
//总度数:90°
double totalDegree = 90;
//卫星菜单半径:这里规定半径或者横坐标都可以。总之就是要为计算每个item的位置服务.
double unit = 300;
//计算当前卫星菜单被及等分了,4个菜单3等分,5个4等分,因此就是items.size()-1等分
double countDegrees = items.size()-1;
//计算出平均等分的度数是多少
double avgDegree = totalDegree / countDegrees;
for (int i = 0;i<items.size();i++) {
//计算当前每个item所占的角度是多少度。从上往下算起(可以根据自己的 布局来定,这里卫星菜单在左上角)
//计算公式为:当前索引*平均度数:此角度 为当前半径和X方向上所成的角,这关系到计算坐标,因此可以根据布局来自己定义怎么计算。
//跟我我的布局这里用cos 函数 来计算:
// x/半径 = cos 当前角度, 因此x = cos当前角度 * 半径;
// y/半径 = sin 当前角度 ,因此y =sin当前角度 * 半径;
//baidu:就拿sin30°为列:Math.sin(30*Math.PI/180)思路为PI相当于π,而此时的PI在角度值里相当于180°,所以Math.PI/180得到的结果就是1°,然后再乘以30就得到相应的30°
double itemDegree = i*avgDegree * Math.PI/180 ;
double itemX = Math.cos(itemDegree) * unit ;
double itemY = Math.sin(itemDegree) * unit ;
TextView item = items.get(i);
PropertyValuesHolder translationX = PropertyValuesHolder.ofFloat("translationX", 0f, (float) itemX);
PropertyValuesHolder translationY = PropertyValuesHolder.ofFloat("translationY", 0f,(float)itemY);
ObjectAnimator o = ObjectAnimator.ofPropertyValuesHolder(item, translationX, translationY);
o.setDuration(500).start();
//插值器:
// o.setInterpolator(new BounceInterpolator());
// o.setInterpolator(new DecelerateInterpolator());
radio.setChecked(true);
animators.add(o);
}
}
}