自定义View实例(一)仿优酷菜单
一、自定义view的几种方式:
- 1.通过Android已有的控件实现自定义效果
- 2.通过继承View类实现自定义View
- 3.通过继承ViewGroup类实现相应效果
二、仿优酷菜单
通过系统控件组合使用,实现仿优酷菜单的效果,效果图:
基本实现思路:
系统基础控件布局+view旋转动画,实现起来也是很简单,布局文件如下,每一级的菜单用RelativeLayout来写是为了方便给菜单中添加按钮
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="@+id/level_1"
android:layout_width="100dp"
android:layout_height="50dp"
android:background="@drawable/level1"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true">
<ImageView
android:id="@+id/ic_home"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/icon_home"
android:layout_centerInParent="true"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/level_2"
android:layout_width="180dp"
android:layout_height="90dp"
android:background="@drawable/level2"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true">
<ImageView
android:id="@+id/ic_search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/icon_search"
android:layout_alignParentBottom="true"
android:layout_margin="10dp"/>
<ImageView
android:id="@+id/ic_menu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/icon_menu"
android:layout_centerHorizontal="true"
android:layout_marginTop="5dp"/>
<ImageView
android:id="@+id/ic_myyouku"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/icon_myyouku"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_margin="10dp"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/level_3"
android:layout_width="280dp"
android:layout_height="140dp"
android:background="@drawable/level3"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true">
<ImageView
android:id="@+id/ic_channerl1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/channel1"
android:layout_alignParentBottom="true"
android:layout_marginBottom="10dp"
android:layout_marginLeft="10dp"/>
<ImageView
android:id="@+id/ic_channerl2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/channel2"
android:layout_above="@id/ic_channerl1"
android:layout_alignLeft="@id/ic_channerl1"
android:layout_marginBottom="10dp"
android:layout_marginLeft="20dp"/>
<ImageView
android:id="@+id/ic_channerl3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/channel3"
android:layout_above="@id/ic_channerl2"
android:layout_alignLeft="@id/ic_channerl2"
android:layout_marginLeft="30dp"
android:layout_marginBottom="6dp"
/>
<ImageView
android:id="@+id/ic_channerl4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/channel4"
android:layout_centerHorizontal="true"
android:layout_marginTop="5dp"/>
<ImageView
android:id="@+id/ic_channerl5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/channel5"
android:layout_above="@id/ic_channerl6"
android:layout_alignRight="@id/ic_channerl6"
android:layout_marginBottom="6dp"
android:layout_marginRight="30dp"
/>
<ImageView
android:id="@+id/ic_channerl6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/channel6"
android:layout_above="@id/ic_channerl7"
android:layout_alignRight="@id/ic_channerl7"
android:layout_marginBottom="6dp"
android:layout_marginRight="20dp"
/>
<ImageView
android:id="@+id/ic_channerl7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/channel7"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginBottom="10dp"
android:layout_marginRight="10dp"/>
</RelativeLayout>
</RelativeLayout>
view动画处理:
用旋转动画RotateAnimation来完成菜单的隐藏和显示,默认的旋转点是view的左上角,我们需要的是以下图所示的点作为中心点,水平右方向为0°,顺时针旋转为正方向,则如下图所示:
动画工具类:
class MyUtils {
/*
默认圆心是view的左上角
水平向右为0°
顺时针旋转度数增加
*/
public static void startAnimOut(RelativeLayout view) {
startAnimOut(view,0);
}
public static void startAnimIn(RelativeLayout view) {
startAnimIn(view,0);
}
public static void startAnimIn(RelativeLayout view, long offset) {
//顺时针进入动画:从180°到360°
RotateAnimation animation = new RotateAnimation(180, 360,
view.getWidth() / 2, view.getHeight());
animation.setDuration(500);
//动画完成后保持最后的状态
animation.setFillAfter(true);
animation.setStartOffset(offset);
view.startAnimation(animation);
}
/*
延时执行动画
*/
public static void startAnimOut(RelativeLayout view, long offset) {
//顺时针离开动画:从0°到180°
RotateAnimation animation = new RotateAnimation(0, 180,
view.getWidth() / 2, view.getHeight());
animation.setDuration(500);
//动画完成后保持最后的状态
animation.setFillAfter(true);
animation.setStartOffset(offset);
view.startAnimation(animation);
}
}
activity中初始化布局然后调用,完整代码:
package com.car.customview;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.KeyEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;
/**
*
*/
public class YouKuMenu extends AppCompatActivity implements View.OnClickListener{
private ImageView icon_home;
private ImageView icon_menu;
private RelativeLayout level1;
private RelativeLayout level2;
private RelativeLayout level3;
private boolean isLevel3Show = true;
private boolean isLevel2Show = true;
private boolean isLevel1Show = true;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_youku_menu);
initView();
}
private void initView() {
icon_home = findViewById(R.id.ic_home);
icon_menu = findViewById(R.id.ic_menu);
level1 = findViewById(R.id.level_1);
level2 = findViewById(R.id.level_2);
level3 = findViewById(R.id.level_3);
icon_menu.setOnClickListener(this);
icon_home.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.ic_menu:
if (isLevel3Show){
//隐藏第三级菜单
MyUtils.startAnimOut(level3);
}else {
//显示第三级菜单
MyUtils.startAnimIn(level3);
}
isLevel3Show = !isLevel3Show;
break;
case R.id.ic_home:
//如果二级菜单显示状态,隐藏二三级菜单
//如果二级菜单隐藏,显示二级菜单
if (isLevel2Show){
MyUtils.startAnimOut(level2);
isLevel2Show = false;
if (isLevel3Show){
MyUtils.startAnimOut(level3,300);
isLevel3Show = false;
}
}else {
MyUtils.startAnimIn(level2);
isLevel2Show = true;
}
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK){
changeLevel1State();
}
return super.onKeyDown(keyCode, event);
}
private void changeLevel1State(){
if (isLevel1Show){
MyUtils.startAnimOut(level1);
isLevel1Show = false;
if (isLevel2Show){
MyUtils.startAnimOut(level2,100);
isLevel2Show = false;
if (isLevel3Show){
MyUtils.startAnimOut(level3,200);
isLevel3Show = false;
}
}
}else {
MyUtils.startAnimIn(level1);
isLevel1Show = true;
MyUtils.startAnimIn(level2,200);
isLevel2Show = true;
}
}
}
基本已经实现了优酷菜单这个自定义view,其中还有一些细节的问题,比如双击home按钮时,上一个动画还没执行完成;因为上述动画使用的是补间动画,所以会导致二级惨淡隐藏后,再点击二级参带的menu所处位置,会弹出三级菜单,这是因为补间动画并不会改变view的属性。
只需要修改工具类里view旋转方法,用属性动画替换补间动画就不会有这个问题了
package com.car.customview;
import android.animation.ObjectAnimator;
import android.widget.RelativeLayout;
class MyUtils {
/*
默认圆心是view的左上角
水平向右为0°
顺时针旋转度数增加
*/
public static void startAnimOut(RelativeLayout view) {
startAnimOut(view,0);
}
public static void startAnimIn(RelativeLayout view) {
startAnimIn(view,0);
}
public static void startAnimIn(RelativeLayout view, long offset) {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view, "rotation",
180,360);
view.setPivotX(view.getWidth() / 2);//设置将要旋转的view的起始点
view.setPivotY(view.getHeight());
objectAnimator.setRepeatCount(0);
objectAnimator.setDuration(500);
objectAnimator.setStartDelay(offset);
objectAnimator.start();
//顺时针进入动画:从180°到360°
/*
RotateAnimation animation = new RotateAnimation(180, 360,
view.getWidth() / 2, view.getHeight());
animation.setDuration(500);
//动画完成后保持最后的状态
animation.setFillAfter(true);
animation.setStartOffset(offset);
view.startAnimation(animation);
*/
}
/*
延时执行动画
*/
public static void startAnimOut(RelativeLayout view, long offset) {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view, "rotation",
0,180);
view.setPivotX(view.getWidth() / 2);
view.setPivotY(view.getHeight());
objectAnimator.setRepeatCount(0);
objectAnimator.setDuration(500);
objectAnimator.setStartDelay(offset);
objectAnimator.start();
//顺时针离开动画:从0°到180°
/*
RotateAnimation animation = new RotateAnimation(0, 180,
view.getWidth() / 2, view.getHeight());
animation.setDuration(500);
//动画完成后保持最后的状态
animation.setFillAfter(true);
animation.setStartOffset(offset);
view.startAnimation(animation);
*/
}
}