啥都先不说,先上效果图
刚开始
点击展开
随便选择一个,ViewPager切换
核心思路是运用属性动画,对该菜单中的每个按钮实行移动。 由于是属性动画,所以不用担心只是动了图片而无法真正的移动这个问题。
由于菜单中要加入许多的按钮,所以我选择的是自定义ViewGroup. 既然是ViewGroup,那我们就需要重写 onMeasure() onLayout() 这两个方法
onMeasure()中,不多说,遍历出子View并且测量他们,通过子View的宽高来确定该ViewGroup的宽高,和弹出后每个按钮之间的间距
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
measureChildren(widthMeasureSpec, heightMeasureSpec);
childMaxWidth = 0;
mMaxHeight = 0;
for (int i = 0; i < mChildCount; i++) {
View child = getChildAt(i);
mMaxHeight = Math.max(mMaxHeight, child.getMeasuredHeight());
childMaxWidth = Math.max(childMaxWidth, child.getMeasuredHeight());
}
//弹出后每个按钮之间的距离
expandPadding = childMaxWidth + padding;
//弹出后菜单的总宽
mMaxnWidth = expandPadding * (mChildCount - 1) + childMaxWidth;
setMeasuredDimension(mMaxnWidth, mMaxHeight);
}
测量完之后是onLayout(),布置各个子View的位置,这里考虑到奇数偶数的时候中心点不一样
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int left = 0;
int top = 0;
int right = 0;
int bottom = 0;
//奇数个子View
if (mChildCount % 2 != 0) {
left = (mMaxnWidth / 2) - (childMaxWidth / 2);
top = 0;
right = (mMaxnWidth / 2) + (childMaxWidth / 2);
bottom = mMaxHeight;
for (int i = 0; i < mChildCount; i++) {
View child = getChildAt(i);
child.layout(left, top, right, bottom);
}
} else {
//偶数个的情况下
left = (mMaxnWidth / 2) + padding / 2;
top = 0;
right = left + childMaxWidth;
bottom = mMaxHeight;
for (int i = 0; i < mChildCount; i++) {
View child = getChildAt(i);
child.layout(left, top, right, bottom);
}
}
}
最后是动画效果
//展开
private void open() {
ObjectAnimator[] oas = new ObjectAnimator[mChildCount];
//整除获取中间值
int middle = mChildCount / 2;
for (int i = 0; i < mChildCount; i++) {
View child = myViews.get(i);
int times = i - middle;
//根据不同位置位移不同距离
ObjectAnimator oa = ObjectAnimator.ofFloat(child, "translationX", expandPadding * times);
oas[i] = oa;
}
AnimatorSet set = new AnimatorSet();
set.setInterpolator(new BounceInterpolator());
set.setDuration(500);
set.playTogether(oas);
set.start();
isExpanded = true;
}
//收起
private void close() {
ObjectAnimator[] oas = new ObjectAnimator[mChildCount];
for (int i = 0; i < mChildCount; i++) {
View child = getChildAt(i);
//属性动画,X轴上位移为0,也就是回归原来的位置
ObjectAnimator oa = ObjectAnimator.ofFloat(child, "translationX", 0);
oas[i] = oa;
}
AnimatorSet set = new AnimatorSet();
set.setDuration(500);
set.playTogether(oas);
set.start();
isExpanded = false;
if (listener != null) {
//点击接口回调
listener.changeBaseView(currentItem);
}
}
最后放上整体代码
public class MenuButtonLayout extends ViewGroup implements View.OnClickListener{
private boolean isExpanded = false;// 菜单是否打开
private int mMaxnWidth;// 总宽度
private int mMaxHeight;// 总高度
private int mChildCount = 0;
private int expandPadding = 200;
private int padding = 20;
private List<View> myViews;
private int childMaxWidth;
private int currentItem;
public MenuButtonLayout(Context context) {
this(context, null);
}
public MenuButtonLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MenuButtonLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setClickable(true);
myViews = new ArrayList<View>();
}
/**
* 设置收起后显示的那个view
*
* @param index
*/
public void setCurrentView(int index) {
View mBaseView = myViews.get(index);
bringChildToFront(mBaseView);
invalidate();
}
/**
* 加入View
*
* @param view
*/
public void addItemView(View view) {
view.setTag(mChildCount);
view.setOnClickListener(this);
addView(view, mChildCount);
myViews.add(view);
mChildCount++;
}
/**
* 测量
*
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
measureChildren(widthMeasureSpec, heightMeasureSpec);
childMaxWidth = 0;
mMaxHeight = 0;
for (int i = 0; i < mChildCount; i++) {
View child = getChildAt(i);
mMaxHeight = Math.max(mMaxHeight, child.getMeasuredHeight());
childMaxWidth = Math.max(childMaxWidth, child.getMeasuredHeight());
}
expandPadding = childMaxWidth + padding;
mMaxnWidth = expandPadding * (mChildCount - 1) + childMaxWidth;
setMeasuredDimension(mMaxnWidth, mMaxHeight);
}
/**
* 布局
*
* @param changed
* @param l
* @param t
* @param r
* @param b
*/
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int left = 0;
int top = 0;
int right = 0;
int bottom = 0;
if (mChildCount % 2 != 0) {
left = (mMaxnWidth / 2) - (childMaxWidth / 2);
top = 0;
right = (mMaxnWidth / 2) + (childMaxWidth / 2);
bottom = mMaxHeight;
for (int i = 0; i < mChildCount; i++) {
View child = getChildAt(i);
child.layout(left, top, right, bottom);
}
} else {
left = (mMaxnWidth / 2) + padding / 2;
top = 0;
right = left + childMaxWidth;
bottom = mMaxHeight;
for (int i = 0; i < mChildCount; i++) {
View child = getChildAt(i);
child.layout(left, top, right, bottom);
}
}
}
/**
* 展开或者收起
*/
private void doMenuAction() {
if (isExpanded) {
close();
} else {
open();
}
}
private void open() {
ObjectAnimator[] oas = new ObjectAnimator[mChildCount];
//整除获取中间值
int middle = mChildCount / 2;
for (int i = 0; i < mChildCount; i++) {
View child = myViews.get(i);
int times = i - middle;
ObjectAnimator oa = ObjectAnimator.ofFloat(child, "translationX", expandPadding * times);
oas[i] = oa;
}
AnimatorSet set = new AnimatorSet();
set.setInterpolator(new BounceInterpolator());
set.setDuration(500);
set.playTogether(oas);
set.start();
isExpanded = true;
}
private void close() {
ObjectAnimator[] oas = new ObjectAnimator[mChildCount];
for (int i = 0; i < mChildCount; i++) {
View child = getChildAt(i);
ObjectAnimator oa = ObjectAnimator.ofFloat(child, "translationX", 0);
oas[i] = oa;
}
AnimatorSet set = new AnimatorSet();
set.setDuration(500);
set.playTogether(oas);
set.start();
isExpanded = false;
if (listener != null) {
listener.changeBaseView(currentItem);
}
}
@Override
public void onClick(View v) {
int index = (int) v.getTag();
currentItem = index;
setCurrentView(index);
doMenuAction();
}
/**
* 设置按钮间距
*/
public void setPadding(int padding) {
this.padding = padding;
}
private onItemClickListener listener;
public interface onItemClickListener {
/**
* 按钮改变回调
*
* @param index 改变按钮的序号
*/
void changeBaseView(int index);
}
public void setOnItemClickListenr(onItemClickListener listenr) {
this.listener = listenr;
}
}
在Activity中的使用
先在布局文件中声明。(这里我就不写了)
然后设置好一些你要展开的按钮
for (int i = 0; i < 5; i++) {
TextView imageView = new TextView(this);
int index = i + 1;
imageView.setText(index + "");
imageView.setGravity(Gravity.CENTER);
imageView.setBackground(getDrawable(R.drawable.already_bid_bade));
menuButtonLayout.addItemView(imageView);
}
//设置显示在最上面的按钮
menuButtonLayout.setCurrentView(0);
给你的菜单加上监听回调
menuButtonLayout.setOnItemClickListenr(new MenuButtonLayout.onItemClickListener() {
@Override
public void changeBaseView(int index) {
Toast.makeText(MainActivity.this, "第" + (index + 1) + "个按钮被点击了", Toast.LENGTH_SHORT).show();
//切换ViewPager
mVp.setCurrentItem(index);
}
});
本人水平并不是很高,可能还有许多不足的地方,希望大家可以指出。