动画效果待后面补充
主要代码如下:
MainActivity
public class MainActivity extends AppCompatActivity {
private static final int ID_BTN_1 = 1;
private static final int ID_BTN_2 = 2;
private static final String ACTION_DOUBLE_CLICK = "android.intent.action.caocong.DOULECLICK";
private HwMenuView mMenuView;
private Button mBtn;
private InnerReceiver mReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
}
private void init() {
mMenuView = findViewById(R.id.menu_view);
List<HwMenuView.MenuItem> menuItems = new ArrayList<>();
menuItems.add(new HwMenuView.MenuItem(ID_BTN_1, R.drawable.btn1, "第一按钮"));
menuItems.add(new HwMenuView.MenuItem(ID_BTN_2, R.drawable.btn2, "第二按钮"));
mMenuView.setAdapter(menuItems);
mMenuView.setOnMenuChangeListener(new HwMenuView.OnMenuChangeListener() {
@Override
public void onMenuChanged(int oldId, int newId) {
switch (oldId) {
case ID_BTN_1:
Toast.makeText(MainActivity.this, "第一个按钮任务完成", Toast.LENGTH_SHORT).show();
break;
case ID_BTN_2:
Toast.makeText(MainActivity.this, "第二个按钮任务完成", Toast.LENGTH_SHORT).show();
break;
default:
break;
}
}
});
mMenuView.setOnMenuSelectListener(new HwMenuView.OnMenuSelectListener() {
@Override
public void onMenuSelected(int viewId) {
switch (viewId) {
case ID_BTN_1:
Toast.makeText(MainActivity.this, "点击第一个按钮", Toast.LENGTH_SHORT).show();
break;
case ID_BTN_2:
Toast.makeText(MainActivity.this, "点击第二个按钮", Toast.LENGTH_SHORT).show();
break;
default:
break;
}
}
});
mBtn = findViewById(R.id.btn);
mBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showMenu();
}
});
mReceiver = new InnerReceiver(this);
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_DOUBLE_CLICK);
registerReceiver(mReceiver, filter);
}
public void showMenu() {
mMenuView.showMenu();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
mMenuView.hidMenu();
return true;
}
private static class InnerReceiver extends BroadcastReceiver {
WeakReference<MainActivity> weakReference;
public InnerReceiver(MainActivity activity) {
weakReference = new WeakReference<>(activity);
}
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION_DOUBLE_CLICK)) {
if (weakReference.get() != null) {
MainActivity activity = weakReference.get();
activity.showMenu();
}
}
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.caocong.arcmenudemo.HwMenuView
android:id="@+id/menu_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right|top">
</com.caocong.arcmenudemo.HwMenuView>
<Button
android:id="@+id/btn"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:text="点击"
android:textColor="#000000"
android:textSize="14sp" />
</FrameLayout>
自定义布局
HwMenuView
public class HwMenuView extends ViewGroup {
private static final String TAG = "caocongTag-HwMenuView";
private static final int WIDTH = 600;
private int mWidth;
private int mHeight;
private MenuLayout mMenuLayout;
public HwMenuView(@NonNull Context context) {
this(context, null, 0);
}
public HwMenuView(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public HwMenuView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mMenuLayout = new MenuLayout(context);
addView(mMenuLayout);
initParms(context);
}
private void initParms(Context context) {
mWidth = WIDTH;
mHeight = WIDTH;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(MeasureSpec.makeMeasureSpec(mWidth, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(mHeight, MeasureSpec.EXACTLY));
measureChildren(MeasureSpec.makeMeasureSpec(mWidth, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(mHeight, MeasureSpec.EXACTLY));
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (getChildCount() == 0) {
return;
}
View child = getChildAt(0);
int childWidth = child.getMeasuredWidth();
int childHeight = child.getMeasuredHeight();
int left = getMeasuredWidth();
int top = -getMeasuredHeight();
int right = left + childWidth;
int bottom = top + childHeight;
Log.d(TAG, "onLayout l t r b is" + left + ";" + top + ";" + right + ";" + bottom);
child.layout(left, top, right, bottom);
}
public void showMenu() {
if (mMenuLayout != null) {
mMenuLayout.showMenu();
}
}
public void hidMenu() {
if (mMenuLayout != null) {
mMenuLayout.hideMenu();
}
}
public void setAdapter(List<MenuItem> menuData) {
if (mMenuLayout != null) {
mMenuLayout.setAdapter(menuData);
}
}
public void setOnMenuSelectListener(OnMenuSelectListener listener){
if (mMenuLayout != null) {
mMenuLayout.setOnMenuSelectListener(listener);
}
}
public void setOnMenuChangeListener(OnMenuChangeListener listener){
if (mMenuLayout != null) {
mMenuLayout.OnMenuChangeListener(listener);
}
}
public interface OnMenuSelectListener {
void onMenuSelected(int viewId);
}
public interface OnMenuChangeListener {
void onMenuChanged(int oldId, int newId);
}
public static class MenuItem {
private int mId;
private int mIconResId;
private String mIconText;
public MenuItem(int id, int iconResId, String iconText) {
mId = id;
mIconResId = iconResId;
mIconText = iconText;
}
public int getId() {
return mId;
}
public int getIconResId() {
return mIconResId;
}
public String getIconText() {
return mIconText;
}
}
}
MenuLayout
public class MenuLayout extends FrameLayout implements View.OnClickListener {
private static final String TAG = "caocongTag";
private static final long TRANS_DURATION = 800L;
private static final long ALPHA_DURATION = 1800L;
private int mWidth;
private int mHeight;
private int mScreenWidth;
private int mScreenHeight;
private int mStokenWidth;
private int mRadiu;
private Paint mArcPaint;
private int mSelectedId = -1;
private List<HwMenuView.MenuItem> mMenuItems;
private HwMenuView.OnMenuSelectListener mOnMenuSelectListener;
private HwMenuView.OnMenuChangeListener mOnMenuChangeListener;
private Animator mRuningAnimator;
/**
* 菜单栏是否正在显示
*/
private boolean mIsShowing;
public MenuLayout(Context context) {
this(context, null, 0);
}
public MenuLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MenuLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setWillNotDraw(false);
initParms(context);
}
private void initParms(Context context) {
DisplayMetrics dm = getResources().getDisplayMetrics();
mScreenWidth = dm.widthPixels;
mScreenHeight = dm.heightPixels;
Log.d(TAG, "screen w h is:" + mScreenWidth + ";" + mScreenHeight);
mArcPaint = new Paint();
mArcPaint.setColor(Color.parseColor("#eeeeee"));
mArcPaint.setAntiAlias(true);
mArcPaint.setStyle(Paint.Style.STROKE);
mArcPaint.setStrokeWidth(250);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
mWidth = MeasureSpec.getSize(widthMeasureSpec);
mHeight = MeasureSpec.getSize(heightMeasureSpec);
mStokenWidth = mWidth / 2;
mRadiu = mWidth - mStokenWidth / 2;
setMeasuredDimension(MeasureSpec.makeMeasureSpec(mWidth, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(mHeight, MeasureSpec.EXACTLY));
int count = getChildCount();
View child;
for (int i = 0; i < count; i++) {
child = getChildAt(i);
int childWidth = 200;
int childHeight = 200;
Log.d(TAG, "onMeasure w h is" + childWidth + ";" + childHeight);
child.measure(MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY));
}
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int count = getChildCount();
View child;
for (int i = 0; i < count; i++) {
child = getChildAt(i);
int childWidth = child.getMeasuredWidth();
int childHeight = child.getMeasuredHeight();
Log.d(TAG, "onLayout child w h is" + childWidth + ";" + childHeight);
int left = mWidth - (int) (mRadiu * Math.cos(2 * Math.PI * 30 * (i + 1) / 360)) - childWidth / 2;
int top = (int) (mRadiu * Math.sin(2 * Math.PI * 30 * (i + 1) / 360)) - childHeight / 2;
int right = left + childWidth;
int bottom = top + childHeight;
Log.d(TAG, "onLayout l t r b is" + left + ";" + top + ";" + right + ";" + bottom);
child.layout(left, top, right, bottom);
}
}
@Override
protected void onDraw(Canvas canvas) {
float left = mStokenWidth / 2;
float top = -(mHeight - mStokenWidth / 2);
float right = 2 * mWidth - mStokenWidth / 2;
float bottom = mHeight - mStokenWidth / 2;
Log.d(TAG, "ondraw l w r b is" + left + ";" + top + ";" + right + ";" + bottom);
RectF rectF = new RectF(left, top, right, bottom);
canvas.drawArc(rectF, 90, 90, false, mArcPaint);
}
public void showMenu() {
if (getVisibility() == GONE) {
setVisibility(VISIBLE);
}
startAnimator();
}
private void startAnimator() {
if (mRuningAnimator != null && mRuningAnimator.isRunning()) {
return;
}
if (mIsShowing){
return;
}
AnimatorSet animationSet = new AnimatorSet();
mRuningAnimator = animationSet;
animationSet.playTogether(getTransAnimator(), getAlphaAnimator());
animationSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mIsShowing = true;
}
});
animationSet.start();
}
@Override
protected boolean onSetAlpha(int alpha) {
return true;
}
private Animator getTransAnimator() {
ValueAnimator transAmin = ValueAnimator.ofFloat(0, 1F);
transAmin.setDuration(TRANS_DURATION);
transAmin.setInterpolator(new LinearInterpolator());
transAmin.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
setTranslationX(-mWidth * value);
setTranslationY(mHeight * value);
}
});
return transAmin;
}
private Animator getAlphaAnimator() {
ValueAnimator alphaAnim = ValueAnimator.ofFloat(0.0F, 1.0F);
alphaAnim.setDuration(ALPHA_DURATION);
alphaAnim.setInterpolator(new LinearInterpolator());
alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
Log.d(TAG, "alpha value" + value);
ViewGroup parentView = (ViewGroup) getParent();
parentView.setAlpha(value);
}
});
return alphaAnim;
}
public void hideMenu() {
setVisibility(GONE);
mIsShowing = false;
}
public void setAdapter(List<HwMenuView.MenuItem> menuData) {
mMenuItems = menuData;
for (int i = 0; i < mMenuItems.size(); i++) {
HwMenuView.MenuItem menuItem = mMenuItems.get(i);
LayoutInflater inflater = LayoutInflater.from(getContext());
MenuView menuView = (MenuView) inflater.inflate(R.layout.menu_item, null);
Drawable drawable = getResources().getDrawable(menuItem.getIconResId());
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
menuView.setCompoundDrawables(null, drawable, null, null);
menuView.setText(menuItem.getIconText());
menuView.setId(menuItem.getId());
menuView.setOnClickListener(this);
addView(menuView);
}
}
@Override
public void addView(View child) {
if (!(child instanceof MenuView)) {
return;
}
super.addView(child);
}
@Override
public void onClick(View view) {
//
if (!(view instanceof MenuView)) {
return;
}
MenuView menuView = (MenuView) view;
int menuViewId = menuView.getId();
if (mSelectedId == -1) {
mSelectedId = menuViewId;
if (mOnMenuSelectListener != null) {
mOnMenuSelectListener.onMenuSelected(view.getId());
}
setChildViewState();
return;
}
//选中后不可再选
if (menuViewId == mSelectedId) {
return;
}
//切换按钮
if (mOnMenuChangeListener != null) {
mOnMenuChangeListener.onMenuChanged(mSelectedId, menuViewId);
}
mSelectedId = menuViewId;
if (mOnMenuSelectListener != null) {
mOnMenuSelectListener.onMenuSelected(mSelectedId);
}
setChildViewState();
}
/**
* 设置菜单的状态
*/
private void setChildViewState() {
int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
if (child.getId() == mSelectedId) {
((MenuView) child).setChecked(true);
child.setEnabled(false);
} else {
((MenuView) child).setChecked(false);
child.setEnabled(true);
}
}
}
public void setOnMenuSelectListener(HwMenuView.OnMenuSelectListener listener) {
mOnMenuSelectListener = listener;
}
public void OnMenuChangeListener(HwMenuView.OnMenuChangeListener listener) {
mOnMenuChangeListener = listener;
}
}
MenuView
public class MenuView extends RadioButton {
public MenuView(Context context) {
this(context,null,0);
}
public MenuView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public MenuView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
menu_item.xml
<?xml version="1.0" encoding="utf-8"?>
<com.caocong.arcmenudemo.MenuView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/btn2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@null"
android:button="@null"
android:gravity="center"
android:textColor="@color/text_color"
android:drawablePadding="0dp"
android:textSize="14sp" />
btn1.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/ic_icon111" android:state_enabled="true"/>
<item android:drawable="@drawable/ic_icon111_gray" android:state_enabled="false"/>
</selector>