自定义控件:用系统自带控件重新组合或者自定义类继承View或者自定义类继承ViewGroup,实现特定的UI效果。
重点:
a.View和ViewGroup的区别
b.Android中事件的传递
c.View的原理
事例一:优酷菜单
由于这里是以中心为旋转点,所以pivotXValue就是view.getWidth()/2,pivotYValue就是view.getHeight()
class Tools {
/**
* 隐藏
* @param view
*/
public static void hideView(View view) {
hideView(view,0);
}
/**
* 显示
* @param view
*/
public static void showView(View view) {
showView(view,0);
}
/**
* 有延迟时间的隐藏
* @param view
* @param startOffset
*/
public static void hideView(View view, int startOffset) {
/**
* fromDegrees 从哪个角度 toDegrees 到哪个角度 水平线为x轴
* pivotXValue pivotYValue 是相对于x y坐标的位置 控件的左上角的坐标为(0,0) 右下角为(1,1)
* 由于这里是以中心为旋转点,所以pivotXValue就是view.getWidth()/2,pivotYValue就是view.getHeight()
*
*/
RotateAnimation animation = new RotateAnimation(0,180,view.getWidth()/2,view.getHeight());
//设置动画的速度
animation.setDuration(500);
//设置动画结束后停留在改变后的位置
animation.setFillAfter(true);
//设置延迟动画时间
animation.setStartOffset(startOffset);
view.startAnimation(animation);
}
/**
* 有延迟时间的显示
* @param view
* @param startOffset
*/
public static void showView(View view, int startOffset) {
RotateAnimation animation = new RotateAnimation(180,360,view.getWidth()/2,view.getHeight());
//设置动画的速度
animation.setDuration(500);
//设置动画结束后停留在改变后的位置
animation.setFillAfter(true);
//设置延迟动画时间
animation.setStartOffset(startOffset);
view.startAnimation(animation);
}
}
问题:如果此时隐藏掉所有的菜单,点击一级菜单会出现bug,因为即使这个视图已经旋转过去,但是它的属性还在,所以可以点击。
如果直接修改成以下代码会无效
/**
* 有延迟时间的隐藏
* @param view
* @param startOffset
*/
public static void hideView(View view, int startOffset) {
/**
* fromDegrees 从哪个角度 toDegrees 到哪个角度 水平线为x轴
* pivotXValue pivotYValue 是相对于x y坐标的位置 控件的左上角的坐标为(0,0) 右下角为(1,1)
* 由于这里是以中心为旋转点,所以pivotXValue就是view.getWidth()/2,pivotYValue就是view.getHeight()
*
*/
RotateAnimation animation = new RotateAnimation(0,180,view.getWidth()/2,view.getHeight());
//设置动画的速度
animation.setDuration(500);
//设置动画结束后停留在改变后的位置
animation.setFillAfter(true);
//设置延迟动画时间
animation.setStartOffset(startOffset);
view.startAnimation(animation);
view.setEnabled(false);
}
/**
* 有延迟时间的显示
* @param view
* @param startOffset
*/
public static void showView(View view, int startOffset) {
RotateAnimation animation = new RotateAnimation(180,360,view.getWidth()/2,view.getHeight());
//设置动画的速度
animation.setDuration(500);
//设置动画结束后停留在改变后的位置
animation.setFillAfter(true);
//设置延迟动画时间
animation.setStartOffset(startOffset);
view.startAnimation(animation);
view.setEnabled(true);
}
因为传进来的view是RelativeLayout,而RelativeLayout是继承ViewGroup的,即使其设置了Enabled,也只是对他自身有效,但是他里面的子view依然可以被点击。
解决办法:
1.将View改为ViewGroup,循环出其子View,并且对每个子View设置Enabled。
2.通过属性动画解决
方法1:
/**
* 有延迟时间的隐藏
* @param view
* @param startOffset
*/
public static void hideView(ViewGroup view, int startOffset) {
/**
* fromDegrees 从哪个角度 toDegrees 到哪个角度 水平线为x轴
* pivotXValue pivotYValue 是相对于x y坐标的位置 控件的左上角的坐标为(0,0) 右下角为(1,1)
* 由于这里是以中心为旋转点,所以pivotXValue就是view.getWidth()/2,pivotYValue就是view.getHeight()
*
*/
RotateAnimation animation = new RotateAnimation(0,180,view.getWidth()/2,view.getHeight());
//设置动画的速度
animation.setDuration(500);
//设置动画结束后停留在改变后的位置
animation.setFillAfter(true);
//设置延迟动画时间
animation.setStartOffset(startOffset);
view.startAnimation(animation);
for (int i = 0;i<view.getChildCount();i++){
View child = view.getChildAt(i);
child.setEnabled(false);
}
}
/**
* 有延迟时间的显示
* @param view
* @param startOffset
*/
public static void showView(ViewGroup view, int startOffset) {
RotateAnimation animation = new RotateAnimation(180,360,view.getWidth()/2,view.getHeight());
//设置动画的速度
animation.setDuration(500);
//设置动画结束后停留在改变后的位置
animation.setFillAfter(true);
//设置延迟动画时间
animation.setStartOffset(startOffset);
view.startAnimation(animation);
for (int i = 0;i<view.getChildCount();i++){
View child = view.getChildAt(i);
child.setEnabled(true);
}
}
android包含三种动画:View Animation(补间)、Drawable Animation(帧动画)、property Animation(属性动画)
View Animation:
基于View的渐变动画,只改变了View的绘制效果,而实际属性未变,比如动画移动一个按钮的位置,但按钮的实际点击位置未变。在代码中定义动画,可以参考AnimationSet类和Animation子类,而如使用Xml,可以在res/anim/文件夹中定义Xml。(事例一则是View Animation)
Drawable Animation:加载一系列的Drawable资源来创建动画,这种传统动画某种程度上就是创建不同图片序列,顺序播放。在代码中定义使用AnimationDawable类;XMl文件更简单的组成动画帧,在res/drawable文件夹,使用<animation-list>采用<item>来定义不同的帧。
property Animation:动画的对象除了是view对象,还可以是Object对象,动画之后,Object对象的属性值被实实在在的改变。view属性改变,view能自动调用invalidate来刷新。
方法2:
/**
* 有延迟时间的隐藏
* @param view
* @param startOffset
*/
public static void hideView(ViewGroup view, int startOffset) {
//使用属性动画
//第一个参数是作用的对象,第二个参数是要改变的属性名,小写
//例子 view.setRotation();
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view,"rotation",0,180);
//设置动画的速度
objectAnimator.setDuration(500);
//设置延迟时间
objectAnimator.setStartDelay(startOffset);
//设置旋转中心
view.setPivotX(view.getWidth()/2);
view.setPivotY(view.getHeight());
objectAnimator.start();
}
/**
* 有延迟时间的显示
* @param view
* @param startOffset
*/
public static void showView(ViewGroup view, int startOffset) {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view,"rotation",180,360);
//设置动画的速度
objectAnimator.setDuration(500);
//设置延迟时间
objectAnimator.setStartDelay(startOffset);
//设置旋转中心
view.setPivotX(view.getWidth()/2);
view.setPivotY(view.getHeight());
objectAnimator.start();
}
更简单的写法:
/**
* 有延迟时间的隐藏
* @param view
* @param startOffset
*/
public static void hideView(ViewGroup view, int startOffset) {
OtherFunction(view,startOffset);
}
/**
* 有延迟时间的显示
* @param view
* @param startOffset
*/
public static void showView(ViewGroup view, int startOffset) {
OtherFunction(view,startOffset);
}
private static void OtherFunction(ViewGroup view, int startOffset) {
//另一种写法
view.setPivotX(view.getWidth()/2);
view.setPivotY(view.getHeight());
view.animate()
.rotationBy(180) //旋转角度
.setDuration(500)
.setStartDelay(startOffset)
.start();
}