自定義控件:用系統(tǒng)自帶控件重新組合或者自定義類繼承View或者自定義類繼承ViewGroup,實(shí)現(xiàn)特定的UI效果。
重點(diǎn):
a.View和ViewGroup的區(qū)別
b.Android中事件的傳遞
c.View的原理
事例一:優(yōu)酷菜單
由于這里是以中心為旋轉(zhuǎn)點(diǎn)片效,所以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);
}
/**
* 有延遲時(shí)間的隱藏
* @param view
* @param startOffset
*/
public static void hideView(View view, int startOffset) {
/**
* fromDegrees 從哪個(gè)角度 toDegrees 到哪個(gè)角度 水平線為x軸
* pivotXValue pivotYValue 是相對(duì)于x y坐標(biāo)的位置 控件的左上角的坐標(biāo)為(0,0) 右下角為(1,1)
* 由于這里是以中心為旋轉(zhuǎn)點(diǎn),所以pivotXValue就是view.getWidth()/2淀衣,pivotYValue就是view.getHeight()
*
*/
RotateAnimation animation = new RotateAnimation(0,180,view.getWidth()/2,view.getHeight());
//設(shè)置動(dòng)畫的速度
animation.setDuration(500);
//設(shè)置動(dòng)畫結(jié)束后停留在改變后的位置
animation.setFillAfter(true);
//設(shè)置延遲動(dòng)畫時(shí)間
animation.setStartOffset(startOffset);
view.startAnimation(animation);
}
/**
* 有延遲時(shí)間的顯示
* @param view
* @param startOffset
*/
public static void showView(View view, int startOffset) {
RotateAnimation animation = new RotateAnimation(180,360,view.getWidth()/2,view.getHeight());
//設(shè)置動(dòng)畫的速度
animation.setDuration(500);
//設(shè)置動(dòng)畫結(jié)束后停留在改變后的位置
animation.setFillAfter(true);
//設(shè)置延遲動(dòng)畫時(shí)間
animation.setStartOffset(startOffset);
view.startAnimation(animation);
}
}
問題:如果此時(shí)隱藏掉所有的菜單昙读,點(diǎn)擊一級(jí)菜單會(huì)出現(xiàn)bug,因?yàn)榧词惯@個(gè)視圖已經(jīng)旋轉(zhuǎn)過去膨桥,但是它的屬性還在蛮浑,所以可以點(diǎn)擊。
如果直接修改成以下代碼會(huì)無效
/**
* 有延遲時(shí)間的隱藏
* @param view
* @param startOffset
*/
public static void hideView(View view, int startOffset) {
/**
* fromDegrees 從哪個(gè)角度 toDegrees 到哪個(gè)角度 水平線為x軸
* pivotXValue pivotYValue 是相對(duì)于x y坐標(biāo)的位置 控件的左上角的坐標(biāo)為(0,0) 右下角為(1,1)
* 由于這里是以中心為旋轉(zhuǎn)點(diǎn)只嚣,所以pivotXValue就是view.getWidth()/2沮稚,pivotYValue就是view.getHeight()
*
*/
RotateAnimation animation = new RotateAnimation(0,180,view.getWidth()/2,view.getHeight());
//設(shè)置動(dòng)畫的速度
animation.setDuration(500);
//設(shè)置動(dòng)畫結(jié)束后停留在改變后的位置
animation.setFillAfter(true);
//設(shè)置延遲動(dòng)畫時(shí)間
animation.setStartOffset(startOffset);
view.startAnimation(animation);
view.setEnabled(false);
}
/**
* 有延遲時(shí)間的顯示
* @param view
* @param startOffset
*/
public static void showView(View view, int startOffset) {
RotateAnimation animation = new RotateAnimation(180,360,view.getWidth()/2,view.getHeight());
//設(shè)置動(dòng)畫的速度
animation.setDuration(500);
//設(shè)置動(dòng)畫結(jié)束后停留在改變后的位置
animation.setFillAfter(true);
//設(shè)置延遲動(dòng)畫時(shí)間
animation.setStartOffset(startOffset);
view.startAnimation(animation);
view.setEnabled(true);
}
因?yàn)閭鬟M(jìn)來的view是RelativeLayout,而RelativeLayout是繼承ViewGroup的册舞,即使其設(shè)置了Enabled蕴掏,也只是對(duì)他自身有效,但是他里面的子view依然可以被點(diǎn)擊调鲸。
解決辦法:
1.將View改為ViewGroup盛杰,循環(huán)出其子View,并且對(duì)每個(gè)子View設(shè)置Enabled藐石。
2.通過屬性動(dòng)畫解決
方法1:
/**
* 有延遲時(shí)間的隱藏
* @param view
* @param startOffset
*/
public static void hideView(ViewGroup view, int startOffset) {
/**
* fromDegrees 從哪個(gè)角度 toDegrees 到哪個(gè)角度 水平線為x軸
* pivotXValue pivotYValue 是相對(duì)于x y坐標(biāo)的位置 控件的左上角的坐標(biāo)為(0,0) 右下角為(1,1)
* 由于這里是以中心為旋轉(zhuǎn)點(diǎn)即供,所以pivotXValue就是view.getWidth()/2,pivotYValue就是view.getHeight()
*
*/
RotateAnimation animation = new RotateAnimation(0,180,view.getWidth()/2,view.getHeight());
//設(shè)置動(dòng)畫的速度
animation.setDuration(500);
//設(shè)置動(dòng)畫結(jié)束后停留在改變后的位置
animation.setFillAfter(true);
//設(shè)置延遲動(dòng)畫時(shí)間
animation.setStartOffset(startOffset);
view.startAnimation(animation);
for (int i = 0;i<view.getChildCount();i++){
View child = view.getChildAt(i);
child.setEnabled(false);
}
}
/**
* 有延遲時(shí)間的顯示
* @param view
* @param startOffset
*/
public static void showView(ViewGroup view, int startOffset) {
RotateAnimation animation = new RotateAnimation(180,360,view.getWidth()/2,view.getHeight());
//設(shè)置動(dòng)畫的速度
animation.setDuration(500);
//設(shè)置動(dòng)畫結(jié)束后停留在改變后的位置
animation.setFillAfter(true);
//設(shè)置延遲動(dòng)畫時(shí)間
animation.setStartOffset(startOffset);
view.startAnimation(animation);
for (int i = 0;i<view.getChildCount();i++){
View child = view.getChildAt(i);
child.setEnabled(true);
}
}
android包含三種動(dòng)畫:View Animation(補(bǔ)間)贯钩、Drawable Animation(幀動(dòng)畫)募狂、property Animation(屬性動(dòng)畫)
View Animation:
基于View的漸變動(dòng)畫办素,只改變了View的繪制效果角雷,而實(shí)際屬性未變,比如動(dòng)畫移動(dòng)一個(gè)按鈕的位置性穿,但按鈕的實(shí)際點(diǎn)擊位置未變勺三。在代碼中定義動(dòng)畫,可以參考AnimationSet類和Animation子類需曾,而如使用Xml吗坚,可以在res/anim/文件夾中定義Xml。(事例一則是View Animation)
Drawable Animation:加載一系列的Drawable資源來創(chuàng)建動(dòng)畫呆万,這種傳統(tǒng)動(dòng)畫某種程度上就是創(chuàng)建不同圖片序列商源,順序播放。在代碼中定義使用AnimationDawable類谋减;XMl文件更簡單的組成動(dòng)畫幀牡彻,在res/drawable文件夾,使用<animation-list>采用<item>來定義不同的幀出爹。
property Animation:動(dòng)畫的對(duì)象除了是view對(duì)象庄吼,還可以是Object對(duì)象缎除,動(dòng)畫之后,Object對(duì)象的屬性值被實(shí)實(shí)在在的改變总寻。view屬性改變器罐,view能自動(dòng)調(diào)用invalidate來刷新。
方法2:
/**
* 有延遲時(shí)間的隱藏
* @param view
* @param startOffset
*/
public static void hideView(ViewGroup view, int startOffset) {
//使用屬性動(dòng)畫
//第一個(gè)參數(shù)是作用的對(duì)象渐行,第二個(gè)參數(shù)是要改變的屬性名轰坊,小寫
//例子 view.setRotation();
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view,"rotation",0,180);
//設(shè)置動(dòng)畫的速度
objectAnimator.setDuration(500);
//設(shè)置延遲時(shí)間
objectAnimator.setStartDelay(startOffset);
//設(shè)置旋轉(zhuǎn)中心
view.setPivotX(view.getWidth()/2);
view.setPivotY(view.getHeight());
objectAnimator.start();
}
/**
* 有延遲時(shí)間的顯示
* @param view
* @param startOffset
*/
public static void showView(ViewGroup view, int startOffset) {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view,"rotation",180,360);
//設(shè)置動(dòng)畫的速度
objectAnimator.setDuration(500);
//設(shè)置延遲時(shí)間
objectAnimator.setStartDelay(startOffset);
//設(shè)置旋轉(zhuǎn)中心
view.setPivotX(view.getWidth()/2);
view.setPivotY(view.getHeight());
objectAnimator.start();
}
更簡單的寫法:
/**
* 有延遲時(shí)間的隱藏
* @param view
* @param startOffset
*/
public static void hideView(ViewGroup view, int startOffset) {
OtherFunction(view,startOffset);
}
/**
* 有延遲時(shí)間的顯示
* @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) //旋轉(zhuǎn)角度
.setDuration(500)
.setStartDelay(startOffset)
.start();
}