传承者(Inheritors)打造共同进步生态圈!!!
转载:http://blog.youkuaiyun.com/lmj623565791/article/details/37567907
三段论:定义属性,自定义ViewGroup,调用
属性定义
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="position" >
<enum name="left_top" value="0"/>
<enum name="right_top" value="1"/>
<enum name="right_bottom" value="2"/>
<enum name="left_bottom" value="3"/>
</attr>
<attr name="radius" format="dimension"/>
<declare-styleable name="ArcMenu">
<attr name="position"/>
<attr name="radius"/>
</declare-styleable>
</resources>
自定义ViewGroup
public class ArcMenu extends ViewGroup implements View.OnClickListener{
/**
* 菜单的显示位置
*/
private Position mPosition = Position.LEFT_TOP;
/**
* 菜单显示的半径,默认100dp
*/
private int mRadius = 100;
/**
* 用户点击的按钮
*/
private View mButton;
/**
* 当前ArcMenu的状态
*/
private Status mCurrentStatus = Status.CLOSE;
/**
* 回调接口
*/
private OnMenuItemClickListener onMenuItemClickListener;
/**
* 状态的枚举
*/
public enum Status{
OPEN,CLOSE
}
/**
* 设置菜单实现的位置,四选一,默认右下
*/
public enum Position{
LEFT_TOP,RIGHT_TOP,RIGHT_BOTTOM,LEFT_BOTTOM
}
public interface OnMenuItemClickListener{
void onClick(View view,int pos);
}
public ArcMenu(Context context) {
this(context,null);
}
public ArcMenu(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public ArcMenu(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
/**
* 初始化属性
*/
mRadius =(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mRadius, getResources().getDisplayMetrics());
TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ArcMenu, defStyleAttr, 0);
int indexCount = typedArray.getIndexCount();
for (int i = 0; i < indexCount; i++) {
int attr = typedArray.getIndex(i);
switch (attr){
case R.styleable.ArcMenu_position:
int val = typedArray.getInt(attr, 0);
switch (val){
case 0:
mPosition = Position.LEFT_TOP;
break;
case 1:
mPosition = Position.RIGHT_TOP;
break;
case 2:
mPosition = Position.RIGHT_BOTTOM;
break;
case 3:
mPosition = Position.LEFT_BOTTOM;
break;
}
break;
case R.styleable.ArcMenu_radius:
mRadius = typedArray.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 100f, getResources().getDisplayMetrics()));
}
}
typedArray.recycle();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int count = getChildCount();
for (int i = 0; i < count; i++) {
getChildAt(i).measure(MeasureSpec.UNSPECIFIED,MeasureSpec.UNSPECIFIED);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
/**
* 为按钮添加点击事件
* @param v
*/
@Override
public void onClick(View v) {
mButton = findViewById(R.id.id_button);
if(mButton == null){
mButton = getChildAt(0);
}
rotateView(mButton,0f,270f,300);
toggleMenu(300);
}
private void toggleMenu(int durationMillis) {
int count = getChildCount();
for (int i = 0; i < count - 1; i++) {
final View childView = getChildAt(i + 1);
childView.setVisibility(VISIBLE);
int xflag = 1;
int yflag = 1;
if(mPosition == Position.LEFT_TOP || mPosition == Position.LEFT_BOTTOM){
xflag = -1;
}
if(mPosition == Position.LEFT_TOP || mPosition == Position.RIGHT_TOP){
yflag = -1;
}
int cl = (int)(mRadius*Math.sin(Math.PI/2/(count - 2)*i));
int ct = (int)(mRadius*Math.cos(Math.PI/2/(count - 2)*i));
AnimationSet animationSet = new AnimationSet(true);
Animation animation = null;
if(mCurrentStatus == Status.CLOSE){
//to open
animationSet.setInterpolator(new OvershootInterpolator(2F));
animation = new TranslateAnimation(xflag*cl,0,yflag*ct,0);
childView.setClickable(true);
childView.setFocusable(true);
}else{//to close
animation = new TranslateAnimation(0f,xflag*cl,0f,yflag*ct);
childView.setFocusable(false);
childView.setClickable(false);
}
animation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
if(mCurrentStatus == Status.CLOSE){
childView.setVisibility(GONE);
}
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
animation.setFillAfter(true);
animation.setDuration(durationMillis);
//为动画设置一个开始延迟时间
animation.setStartOffset((i*100)/(count - 1));
RotateAnimation rotate = new RotateAnimation(0,720,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
rotate.setDuration(durationMillis);
rotate.setFillAfter(true);
animationSet.addAnimation(rotate);
animationSet.addAnimation(animation);
childView.startAnimation(animationSet);
final int index = i+1;
childView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(onMenuItemClickListener != null){
onMenuItemClickListener.onClick(childView, index - 1);
menuItemAnim(index -1);
changeStatus();
}
}
});
}
changeStatus();
}
private void changeStatus() {
mCurrentStatus = (mCurrentStatus == Status.CLOSE?Status.OPEN : Status.CLOSE);
}
/**
* 开始菜单动画,点击的MenuItem放大消失,其他的缩小消失
* @param item
*/
private void menuItemAnim(int item) {
for (int i = 0; i < getChildCount() - 1; i++) {
View childView = getChildAt(i+1);
if(i == item){
childView.startAnimation(scaleBigAnim(300));
}else{
childView.startAnimation(scaleSmallAnim(300));
}
childView.setClickable(false);
childView.setFocusable(false);
}
}
/**
* 缩小消失
* @param durationMills
* @return
*/
private Animation scaleSmallAnim(int durationMills) {
Animation anim = new ScaleAnimation(1.0f,0f,1.0f,0f,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
anim.setDuration(durationMills);
anim.setFillAfter(true);
return anim;
}
/**
* 放大,透明度降低
* @param durationMills
* @return
*/
private Animation scaleBigAnim(int durationMills) {
AnimationSet animationset = new AnimationSet(true);
Animation anim = new ScaleAnimation(1.0f,4.0f,1.0f,4.0f,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
Animation alphaAnimation = new AlphaAnimation(1,0);
animationset.addAnimation(anim);
animationset.addAnimation(alphaAnimation);
animationset.setDuration(durationMills);
animationset.setFillAfter(true);
return animationset;
}
/**
* 按钮的旋转动画
*
*/
private void rotateView(View view, float fromDegrees, float toDegrees, int durationMillis) {
RotateAnimation rotate = new RotateAnimation(fromDegrees,toDegrees, Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
rotate.setDuration(durationMillis);
rotate.setFillAfter(true);
view.startAnimation(rotate);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if(changed){
layoutButton();
int count = getChildCount();
/**
* 设置所有孩子的位置例如
* (第一个按钮):左上时,从左到右,
* 第二个:mRadius(sinθ,cosθ)α= Math.PI/2*(cCount_1)
* 第三个按钮mRadius(sinα,cosα)
* 第四个:mRadius(sin2α,cos2α)
* 第五个:mRadius(sin3α,cos3α)
*/
for (int i = 0; i <count -1 ; i++) {
View child =getChildAt(i+1);
child.setVisibility(View.GONE);
int cl = (int) (mRadius * Math.sin(Math.PI / 2 / (count - 2) * i));
int ct = (int)(mRadius*Math.cos(Math.PI/2/(count - 2)*i));
int cWidth = child.getMeasuredWidth();
int cHeight = child.getMeasuredHeight();
//左下,右下
if(mPosition == Position.LEFT_BOTTOM || mPosition == Position.RIGHT_BOTTOM){
ct = getMeasuredHeight() - cHeight - ct;
}
//右上,右下
if(mPosition == Position.RIGHT_TOP || mPosition == Position.RIGHT_BOTTOM){
cl = getMeasuredWidth() - cWidth - cl;
}
child.layout(cl,ct,cl+cWidth,ct+cHeight);
}
}
}
/**
* 第一个子元素为按钮,为俺就布局且初始化点击事件
*/
private void layoutButton() {
View cButton = getChildAt(0);
cButton.setOnClickListener(this);
int l= 0;
int t = 0;
int width = cButton.getMeasuredWidth();
int height = cButton.getMeasuredHeight();
switch (mPosition){
case LEFT_TOP:
l = 0;
t = 0;
break;
case LEFT_BOTTOM:
l = 0;
t = getMeasuredHeight() - height;
break;
case RIGHT_TOP:
l = getMeasuredWidth() - width;
t = 0;
break;
case RIGHT_BOTTOM:
l = getMeasuredWidth() - width;
t = getMeasuredHeight() - height;
break;
}
cButton.layout(l,t,l+width,t+height);
}
public Position getmPosition()
{
return mPosition;
}
public void setmPosition(Position mPosition)
{
this.mPosition = mPosition;
}
public int getmRadius()
{
return mRadius;
}
public void setmRadius(int mRadius)
{
this.mRadius = mRadius;
}
public Status getmCurrentStatus()
{
return mCurrentStatus;
}
public void setmCurrentStatus(Status mCurrentStatus)
{
this.mCurrentStatus = mCurrentStatus;
}
public OnMenuItemClickListener getOnMenuItemClickListener()
{
return onMenuItemClickListener;
}
public void setOnMenuItemClickListener(
OnMenuItemClickListener onMenuItemClickListener)
{
this.onMenuItemClickListener = onMenuItemClickListener;
}
}
布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xxl="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<com.example.administrator.testapplication.ArcMenu
android:id="@+id/id_arcmenu1"
android:layout_width="match_parent"
android:layout_height="match_parent"
xxl:position="left_top"
xxl:radius="130dp"
>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@mipmap/composer_button" >
<ImageView
android:id="@+id/id_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@mipmap/composer_icn_plus" />
</RelativeLayout>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@mipmap/composer_camera"
android:tag="Camera" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@mipmap/composer_sun"
android:tag="Sun" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@mipmap/composer_place"
android:tag="Place" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@mipmap/composer_sleep"
android:tag="Sleep" />
</com.example.administrator.testapplication.ArcMenu>
<com.example.administrator.testapplication.ArcMenu
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xxl:position="right_bottom"
xxl:radius="130dp" >
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@mipmap/composer_button" >
<ImageView
android:id="@+id/id_button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@mipmap/composer_icn_plus" />
</RelativeLayout>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@mipmap/composer_camera"
android:tag="Camera" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@mipmap/composer_sun"
android:tag="Sun" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@mipmap/composer_place"
android:tag="Place" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@mipmap/composer_sleep"
android:tag="Sleep" />
</com.example.administrator.testapplication.ArcMenu>
<com.example.administrator.testapplication.ArcMenu
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xxl:position="left_bottom"
xxl:radius="130dp" >
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@mipmap/composer_button" >
<ImageView
android:id="@+id/id_button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@mipmap/composer_icn_plus" />
</RelativeLayout>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@mipmap/composer_sun"
android:tag="Sun" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@mipmap/composer_place"
android:tag="Place" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@mipmap/composer_sleep"
android:tag="Sleep" />
</com.example.administrator.testapplication.ArcMenu>
<com.example.administrator.testapplication.ArcMenu
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xxl:position="right_top"
xxl:radius="130dp" >
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@mipmap/composer_button" >
<ImageView
android:id="@+id/id_button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@mipmap/composer_icn_plus" />
</RelativeLayout>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@mipmap/composer_camera"
android:tag="Camera" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@mipmap/composer_sun"
android:tag="Sun" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@mipmap/composer_place"
android:tag="Place" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@mipmap/composer_sleep"
android:tag="Sleep" />
</com.example.administrator.testapplication.ArcMenu>
</RelativeLayout >
调用
public class MainActivity extends Activity {
private ArcMenu mArcMenuLeftTop;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mArcMenuLeftTop = (ArcMenu) findViewById(R.id.id_arcmenu1);
//添加动态的一个MenuItem
ImageView people = new ImageView(this);
people.setImageResource(R.mipmap.composer_with);
people.setTag("People");
mArcMenuLeftTop.addView(people);
mArcMenuLeftTop.setOnMenuItemClickListener(new ArcMenu.OnMenuItemClickListener() {
@Override
public void onClick(View view, int pos) {
Toast.makeText(MainActivity.this,pos + ":" + view.getTag(), Toast.LENGTH_SHORT).show();
}
});
}
}
思考
- 对于容器自定义各种view计算初始位置,计算结束位置,在位置之间转换添加相应的动画特效,彰显视觉艺术!