效果展示

good_view.gif
github地址:
點(diǎn)贊效果(含詳細(xì)解)源碼
ps:只是fork下來的,囧
知識(shí)儲(chǔ)備:
1,清楚了解Androidview的坐標(biāo)系
2,清楚了解View.MeasureSpec類
3,清楚了解集合動(dòng)畫
沒了解過的親,建議先找相關(guān)文章閱讀了解清楚
解析流程:
1,實(shí)現(xiàn)思路:
繼承PopupWindow,設(shè)置寬高,彈出位置,動(dòng)畫效果.
實(shí)現(xiàn)思路看起來挺簡單的,難點(diǎn)在于
a,popwindow的彈出定位,需要對(duì)view的坐標(biāo)系比較熟悉
b,popwindow的大小計(jì)算,需要對(duì)View.MeasureSpec熟悉
c,popwindow的動(dòng)畫效果,組合動(dòng)畫,透明度以及位移動(dòng)畫.位移動(dòng)畫初始位置需要搞清楚.
2,難點(diǎn)解析
a,彈出定位
overwrite popwindow show(View v)
核心代碼:
int offsetX = v.getWidth() / 2 - getWidth() / 2;//X方向上的偏移量
int offsetY = -v.getHeight() - getHeight();//Y方向上的偏移量
showAsDropDown(v,offsetX , offsetY);
定位圖

popwindow定位圖.jpg
關(guān)鍵點(diǎn)
1,知道Popwindow.showAsDropDown()方法的坐標(biāo)原點(diǎn)在view的左下方!!!
2,在該坐標(biāo)下,已知view和popwindow各自的寬高,計(jì)算偏移坐標(biāo)
(貌似初中知識(shí),囧)
計(jì)算寬高
在構(gòu)造方法中計(jì)算寬高
//根據(jù)提供的大小值和模式,創(chuàng)建一個(gè)測量值(格式)
int w = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);//未指定模式,子元素大小任意.
int h = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
mGoodTv.measure(w, h);
setWidth(mGoodTv.getMeasuredWidth());
setHeight(mDistance + mGoodTv.getMeasuredHeight());
在設(shè)置文字后計(jì)算寬高
int w = (int) mGoodTv.getPaint().measureText(text);
setWidth(w);
setHeight(mDistance + getTextViewHeight(mGoodTv, w));
private static int getTextViewHeight(TextView textView, int width) {
int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.AT_MOST);//最多不超過width
int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
textView.measure(widthMeasureSpec, heightMeasureSpec);
return textView.getMeasuredHeight();
}
在設(shè)置圖片后計(jì)算寬高
/**
* 設(shè)置圖片
*
* @param drawable
*/
public void setImage(Drawable drawable) {
if (drawable == null) {
throw new IllegalArgumentException("drawable cannot be null.");
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
mGoodTv.setBackground(drawable);
} else {
mGoodTv.setBackgroundDrawable(drawable);
}
/*******************************************************************/
//drawable獲取實(shí)際寬高的方式
mGoodTv.setText("");
setWidth(drawable.getIntrinsicWidth());//獲取drawable實(shí)際寬高
//加上mDistance 移動(dòng)動(dòng)畫不會(huì)被遮蓋
setHeight(mDistance + drawable.getIntrinsicHeight());
/*******************************************************************/
}
c,動(dòng)畫
/**
* 動(dòng)畫
*
* @return
*/
private AnimationSet createAnimation() {
mAnimationSet = new AnimationSet(true);
/**
* 核心代碼
* *****************************************************************/
TranslateAnimation translateAnim = new TranslateAnimation(0, 0, mFromY, -mToY);
/*******************************************************************/
AlphaAnimation alphaAnim = new AlphaAnimation(mFromAlpha, mToAlpha);
mAnimationSet.addAnimation(translateAnim);
mAnimationSet.addAnimation(alphaAnim);
mAnimationSet.setDuration(mDuration);
mAnimationSet.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
if (isShowing()) {
new Handler().post(new Runnable() {
@Override
public void run() {
dismiss();
}
});
}
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
return mAnimationSet;
}