优酷菜单 下拉菜单
- 组合式的控件
- 补间动画:
- 是通过父容器来不停的绘制孩子的形状
- 步骤:
- 创建布局
- 创建一个类,继承布局的根View
- 将业务逻辑封装到类中
- 特点:
- 将原生的view进行组装
- 加入业务逻辑
<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" >
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true" >
<!-- 外侧 -->
<RelativeLayout
android:id="@+id/level3"
android:layout_width="280dp"
android:layout_height="140dp"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:background="@drawable/level3" >
<!-- channel1 -->
<ImageView
android:id="@+id/level3_channel1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginLeft="8dp"
android:src="@drawable/channel1" />
<!-- channel2 -->
<ImageView
android:id="@+id/level3_channel2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/level3_channel1"
android:layout_marginBottom="12dp"
android:layout_marginLeft="30dp"
android:src="@drawable/channel2" />
<!-- channel3 -->
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/level3_channel2"
android:layout_marginBottom="12dp"
android:layout_marginLeft="60dp"
android:src="@drawable/channel3" />
<!-- channel4 -->
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="5dp"
android:src="@drawable/channel4" />
<!-- channel7 -->
<ImageView
android:id="@+id/level3_channel7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginRight="8dp"
android:src="@drawable/channel7" />
<!-- channel6 -->
<ImageView
android:id="@+id/level3_channel6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/level3_channel7"
android:layout_alignParentRight="true"
android:layout_marginBottom="12dp"
android:layout_marginRight="30dp"
android:src="@drawable/channel6" />
<!-- channel5 -->
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/level3_channel6"
android:layout_alignParentRight="true"
android:layout_marginBottom="12dp"
android:layout_marginRight="60dp"
android:src="@drawable/channel5" />
</RelativeLayout>
<!-- 中间 -->
<RelativeLayout
android:id="@+id/level2"
android:layout_width="180dp"
android:layout_height="90dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:background="@drawable/level2" >
<!-- 搜索图标 -->
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginLeft="8dp"
android:src="@drawable/icon_search" />
<!-- 菜单图标 -->
<ImageView
android:id="@+id/level2_menu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="5dp"
android:src="@drawable/icon_menu" />
<!-- youku -->
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginRight="8dp"
android:src="@drawable/icon_myyouku" />
</RelativeLayout>
<!-- 内侧 -->
<RelativeLayout
android:id="@+id/level1"
android:layout_width="100dp"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:background="@drawable/level1" >
<!-- home图标 -->
<ImageView
android:id="@+id/level1_home"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@drawable/icon_home" />
</RelativeLayout>
</RelativeLayout>
</RelativeLayout>
public class MainActivity extends Activity implements OnClickListener {
private ImageView mIvHome;
private ImageView mIvMenu;
private boolean isLevel1Display = true;// 用来标记内侧的容器是否显示
private boolean isLevel2Display = true;// 用来标记中间的容器是否显示
private boolean isLevel3Display = true;// 用来标记外侧的容器是否显示
private RelativeLayout mLevel1;// 内侧的容器
private RelativeLayout mLevel2;// 中间的容器
private RelativeLayout mLevel3;// 外侧的容器
private int mCurrentAnimationCount = 0;// 用来记录当前动画的个数
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
mIvHome = (ImageView) findViewById(R.id.level1_home);
mIvMenu = (ImageView) findViewById(R.id.level2_menu);
mLevel1 = (RelativeLayout) findViewById(R.id.level1);
mLevel2 = (RelativeLayout) findViewById(R.id.level2);
mLevel3 = (RelativeLayout) findViewById(R.id.level3);
// 设置点击事件
mIvHome.setOnClickListener(this);
mIvMenu.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v == mIvHome) {
clickLevel1Home();
} else if (v == mIvMenu) {
clickLevel2Menu();
}
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
// keyCode点击的按钮
if (keyCode == KeyEvent.KEYCODE_MENU) {
System.out.println("点击了实体menu");
clickHardwareMenu();
// 如果点击的是menu按钮,就去消费掉这个点击事件,不向下传递
return true;
}
return super.onKeyUp(keyCode, event);
}
/**
* 点击实体的menu按钮
*/
private void clickHardwareMenu() {
// 如果现在正在有动画在执行的情况下,就不去执行点击的逻辑
if (mCurrentAnimationCount != 0) {
return;
}
// 如果全部可见,就全部收起来
if (isLevel1Display && isLevel2Display && isLevel3Display) {
hiddenLevel(mLevel1, 200);
hiddenLevel(mLevel2, 100);
hiddenLevel(mLevel3, 0);// 不需要延时
// 状态
isLevel1Display = false;
isLevel2Display = false;
isLevel3Display = false;
return;
}
// 如果全部都不显示,全部显示
if (!isLevel1Display && !isLevel2Display && !isLevel3Display) {
showLevel(mLevel1, 0);
showLevel(mLevel2, 100);
showLevel(mLevel3, 200);
// 状态
isLevel1Display = true;
isLevel2Display = true;
isLevel3Display = true;
return;
}
// 如果外侧不可见,内侧和中间可见,全部不见
if (!isLevel3Display && isLevel1Display && isLevel2Display) {
hiddenLevel(mLevel1, 100);
hiddenLevel(mLevel2, 0);
isLevel1Display = false;
isLevel2Display = false;
return;
}
if (!isLevel3Display && !isLevel2Display && isLevel1Display) {
// 隐藏level1
hiddenLevel(mLevel1, 0);
isLevel1Display = false;
return;
}
}
// 当点击中间的menu按钮
private void clickLevel2Menu() {
// 如果现在正在有动画在执行的情况下,就不去执行点击的逻辑
if (mCurrentAnimationCount != 0) {
return;
}
// 如果外侧可见,隐藏外侧
if (isLevel3Display) {
// 隐藏外侧
hiddenLevel(mLevel3, 0);
// 设置状态
isLevel3Display = false;
} else {
showLevel(mLevel3, 0);
isLevel3Display = true;
}
}
// 点击home按钮的逻辑操作
private void clickLevel1Home() {
// 点击内侧的home
// 如果现在正在有动画在执行的情况下,就不去执行点击的逻辑
if (mCurrentAnimationCount != 0) {
return;
}
// 如果外侧和中间都显示的情况下, 收起外侧和中间
if (isLevel2Display && isLevel3Display) {
// 收起外侧和中间
// 动画的去关闭view
hiddenLevel(mLevel2, 100);
hiddenLevel(mLevel3, 0);
// 改变状态记录
isLevel2Display = false;
isLevel3Display = false;
return;
}
// 如果外侧和中间都不显示的情况下,只显示中间
if (!isLevel2Display && !isLevel3Display) {
// 去显示中间的
showLevel(mLevel2, 0);
// 状态的改变
isLevel2Display = true;
return;
}
// 如果只显示中间,不显示外侧的情况下,收起中间
if (isLevel2Display && !isLevel3Display) {
// 收起中间
hiddenLevel(mLevel2, 0);
// 状态的改变
isLevel2Display = false;
return;
}
}
/**
* 动画的隐藏level
*
* @param level
* @param startOffset
*/
private void hiddenLevel(ViewGroup level, long startOffset) {
// 动画的去阴影
// 让viewGroup和他的孩子不可用
level.setEnabled(false);
int count = level.getChildCount();
for (int i = 0; i < count; i++) {
level.getChildAt(i).setEnabled(false);
}
// 做旋转动画
RotateAnimation rotate = new RotateAnimation(0,// 起始的角度
-180, // 旋转的角度
RotateAnimation.RELATIVE_TO_SELF,// 旋转的中轴的x是相对谁的
0.5f, RotateAnimation.RELATIVE_TO_SELF, 1f);
rotate.setDuration(400);
rotate.setFillAfter(true);// 保持为旋转后的位置
rotate.setStartOffset(startOffset);// 设置动画的延时
rotate.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
// 动画开启
mCurrentAnimationCount++;
}
@Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationEnd(Animation animation) {
// 动画结束
mCurrentAnimationCount--;
}
});
level.startAnimation(rotate);
}
private void showLevel(ViewGroup level, long startOffset) {
// 动画的去阴影
level.setEnabled(true);
int count = level.getChildCount();
for (int i = 0; i < count; i++) {
level.getChildAt(i).setEnabled(true);
}
// 做旋转动画
RotateAnimation rotate = new RotateAnimation(-180,// 起始的角度
0, // 旋转的角度
RotateAnimation.RELATIVE_TO_SELF,// 旋转的中轴的x是相对谁的
0.5f, RotateAnimation.RELATIVE_TO_SELF, 1f);
rotate.setDuration(400);
rotate.setFillAfter(true);// 保持为旋转后的位置
rotate.setStartOffset(startOffset);// 设置动画的延时
rotate.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
// 动画开启
mCurrentAnimationCount++;
}
@Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationEnd(Animation animation) {
// 动画结束
mCurrentAnimationCount--;
}
});
level.startAnimation(rotate);
}
}
封装:
public class YoukuMenu extends RelativeLayout implements OnClickListener {
private ImageView mIvHome;
private ImageView mIvMenu;
private boolean isLevel1Display = true;// 用来标记内侧的容器是否显示
private boolean isLevel2Display = true;// 用来标记中间的容器是否显示
private boolean isLevel3Display = true;// 用来标记外侧的容器是否显示
private RelativeLayout mLevel1;// 内侧的容器
private RelativeLayout mLevel2;// 中间的容器
private RelativeLayout mLevel3;// 外侧的容器
private int mCurrentAnimationCount = 0;// 用来记录当前动画的个数
// new
public YoukuMenu(Context context) {
this(context, null);
}
// xml
public YoukuMenu(Context context, AttributeSet attrs) {
super(context, attrs);
// 将xml挂载到class上
View.inflate(context, R.layout.youku_menu, this);
initView();
}
private void initView() {
// 设置focus
setFocusableInTouchMode(true);
mIvHome = (ImageView) findViewById(R.id.level1_home);
mIvMenu = (ImageView) findViewById(R.id.level2_menu);
mLevel1 = (RelativeLayout) findViewById(R.id.level1);
mLevel2 = (RelativeLayout) findViewById(R.id.level2);
mLevel3 = (RelativeLayout) findViewById(R.id.level3);
// 设置点击事件
mIvHome.setOnClickListener(this);
mIvMenu.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v == mIvHome) {
clickLevel1Home();
} else if (v == mIvMenu) {
clickLevel2Menu();
}
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
// keyCode点击的按钮
if (keyCode == KeyEvent.KEYCODE_MENU) {
System.out.println("点击了实体menu");
clickHardwareMenu();
// 如果点击的是menu按钮,就去消费掉这个点击事件,不向下传递
return true;
}
return super.onKeyUp(keyCode, event);
}
/**
* 点击实体的menu按钮
*/
private void clickHardwareMenu() {
// 如果现在正在有动画在执行的情况下,就不去执行点击的逻辑
if (mCurrentAnimationCount != 0) {
return;
}
// 如果全部可见,就全部收起来
if (isLevel1Display && isLevel2Display && isLevel3Display) {
hiddenLevel(mLevel1, 200);
hiddenLevel(mLevel2, 100);
hiddenLevel(mLevel3, 0);// 不需要延时
// 状态
isLevel1Display = false;
isLevel2Display = false;
isLevel3Display = false;
return;
}
// 如果全部都不显示,全部显示
if (!isLevel1Display && !isLevel2Display && !isLevel3Display) {
showLevel(mLevel1, 0);
showLevel(mLevel2, 100);
showLevel(mLevel3, 200);
// 状态
isLevel1Display = true;
isLevel2Display = true;
isLevel3Display = true;
return;
}
// 如果外侧不可见,内侧和中间可见,全部不见
if (!isLevel3Display && isLevel1Display && isLevel2Display) {
hiddenLevel(mLevel1, 100);
hiddenLevel(mLevel2, 0);
isLevel1Display = false;
isLevel2Display = false;
return;
}
if (!isLevel3Display && !isLevel2Display && isLevel1Display) {
// 隐藏level1
hiddenLevel(mLevel1, 0);
isLevel1Display = false;
return;
}
}
// 当点击中间的menu按钮
private void clickLevel2Menu() {
// 如果现在正在有动画在执行的情况下,就不去执行点击的逻辑
if (mCurrentAnimationCount != 0) {
return;
}
// 如果外侧可见,隐藏外侧
if (isLevel3Display) {
// 隐藏外侧
hiddenLevel(mLevel3, 0);
// 设置状态
isLevel3Display = false;
} else {
showLevel(mLevel3, 0);
isLevel3Display = true;
}
}
// 点击home按钮的逻辑操作
private void clickLevel1Home() {
// 点击内侧的home
// 如果现在正在有动画在执行的情况下,就不去执行点击的逻辑
if (mCurrentAnimationCount != 0) {
return;
}
// 如果外侧和中间都显示的情况下, 收起外侧和中间
if (isLevel2Display && isLevel3Display) {
// 收起外侧和中间
// 动画的去关闭view
hiddenLevel(mLevel2, 100);
hiddenLevel(mLevel3, 0);
// 改变状态记录
isLevel2Display = false;
isLevel3Display = false;
return;
}
// 如果外侧和中间都不显示的情况下,只显示中间
if (!isLevel2Display && !isLevel3Display) {
// 去显示中间的
showLevel(mLevel2, 0);
// 状态的改变
isLevel2Display = true;
return;
}
// 如果只显示中间,不显示外侧的情况下,收起中间
if (isLevel2Display && !isLevel3Display) {
// 收起中间
hiddenLevel(mLevel2, 0);
// 状态的改变
isLevel2Display = false;
return;
}
}
/**
* 动画的隐藏level
*
* @param level
* @param startOffset
*/
private void hiddenLevel(ViewGroup level, long startOffset) {
// 动画的去阴影
// 让viewGroup和他的孩子不可用
level.setEnabled(false);
int count = level.getChildCount();
for (int i = 0; i < count; i++) {
level.getChildAt(i).setEnabled(false);
}
// 做旋转动画
RotateAnimation rotate = new RotateAnimation(0,// 起始的角度
-180, // 旋转的角度
RotateAnimation.RELATIVE_TO_SELF,// 旋转的中轴的x是相对谁的
0.5f, RotateAnimation.RELATIVE_TO_SELF, 1f);
rotate.setDuration(400);
rotate.setFillAfter(true);// 保持为旋转后的位置
rotate.setStartOffset(startOffset);// 设置动画的延时
rotate.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
// 动画开启
mCurrentAnimationCount++;
}
@Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationEnd(Animation animation) {
// 动画结束
mCurrentAnimationCount--;
}
});
level.startAnimation(rotate);
}
private void showLevel(ViewGroup level, long startOffset) {
// 动画的去阴影
level.setEnabled(true);
int count = level.getChildCount();
for (int i = 0; i < count; i++) {
level.getChildAt(i).setEnabled(true);
}
// 做旋转动画
RotateAnimation rotate = new RotateAnimation(-180,// 起始的角度
0, // 旋转的角度
RotateAnimation.RELATIVE_TO_SELF,// 旋转的中轴的x是相对谁的
0.5f, RotateAnimation.RELATIVE_TO_SELF, 1f);
rotate.setDuration(400);
rotate.setFillAfter(true);// 保持为旋转后的位置
rotate.setStartOffset(startOffset);// 设置动画的延时
rotate.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
// 动画开启
mCurrentAnimationCount++;
}
@Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationEnd(Animation animation) {
// 动画结束
mCurrentAnimationCount--;
}
});
level.startAnimation(rotate);
}
}
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<!-- 外侧 -->
<RelativeLayout
android:id="@+id/level3"
android:layout_width="280dp"
android:layout_height="140dp"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:background="@drawable/level3" >
<!-- channel1 -->
<ImageView
android:id="@+id/level3_channel1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginLeft="8dp"
android:src="@drawable/channel1" />
<!-- channel2 -->
<ImageView
android:id="@+id/level3_channel2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/level3_channel1"
android:layout_marginBottom="12dp"
android:layout_marginLeft="30dp"
android:src="@drawable/channel2" />
<!-- channel3 -->
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/level3_channel2"
android:layout_marginBottom="12dp"
android:layout_marginLeft="60dp"
android:src="@drawable/channel3" />
<!-- channel4 -->
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="5dp"
android:src="@drawable/channel4" />
<!-- channel7 -->
<ImageView
android:id="@+id/level3_channel7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginRight="8dp"
android:src="@drawable/channel7" />
<!-- channel6 -->
<ImageView
android:id="@+id/level3_channel6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/level3_channel7"
android:layout_alignParentRight="true"
android:layout_marginBottom="12dp"
android:layout_marginRight="30dp"
android:src="@drawable/channel6" />
<!-- channel5 -->
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/level3_channel6"
android:layout_alignParentRight="true"
android:layout_marginBottom="12dp"
android:layout_marginRight="60dp"
android:src="@drawable/channel5" />
</RelativeLayout>
<!-- 中间 -->
<RelativeLayout
android:id="@+id/level2"
android:layout_width="180dp"
android:layout_height="90dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:background="@drawable/level2" >
<!-- 搜索图标 -->
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginLeft="8dp"
android:src="@drawable/icon_search" />
<!-- 菜单图标 -->
<ImageView
android:id="@+id/level2_menu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="5dp"
android:src="@drawable/icon_menu" />
<!-- youku -->
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginRight="8dp"
android:src="@drawable/icon_myyouku" />
</RelativeLayout>
<!-- 内侧 -->
<RelativeLayout
android:id="@+id/level1"
android:layout_width="100dp"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:background="@drawable/level1" >
<!-- home图标 -->
<ImageView
android:id="@+id/level1_home"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@drawable/icon_home" />
</RelativeLayout>
</RelativeLayout>
public class DemoActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_demo);
}
}
参考:Android自定义控件