记得以前刚开始学安卓的时候,做过一个模仿蜻蜓FM的Demo。他那里面的每个List元素都是一个自定义View。当时没时间做,就跳过去。在上个公司很少写自定义View,感觉都有点生疏了。正巧赶上过年有空,并且感觉这个自定义View挺简单。拿出了半天的时间简单的实现下练练手。
先看看他们的app的布局
自定义虽然麻烦,但是可以减少布局的层次。我们就来实现他这个单独的自定义View,并且单独一个View在代码里面使用起来也更方便简单。
首先是构造函数,对于这个自定义V iew我们给它留四个styleable。
<declare-styleable name="QingtingView1" >
<attr name="isNeedTimeStamp" format="boolean" />
<attr name="isNeedStar" format="boolean" />
<attr name="TitleTextSize" format="dimension"/>
<attr name="DesTextSize" format="dimension"/>
</declare-styleable>
分别来指定它是否需要时间戳,是否需要星级描述,以及标题和描述的字体大小
public QingTingView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.QingtingView1, defStyleAttr, 0);
for(int count = a.getIndexCount(); count > 0; count --){
int attr = a.getIndex(count);
switch (attr){
case R.styleable.QingtingView1_isNeedStar :
isNeedStar = a.getBoolean(attr, false);
case R.styleable.QingtingView1_isNeedTimeStamp :
isNeedTimeStamp = a.getBoolean(attr, false);
case R.styleable.QingtingView1_TitleTextSize:
mTitleTextSize = a.getDimensionPixelSize(attr, (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,16,getResources().getDisplayMetrics()));
case R.styleable.QingtingView1_DesTextSize:
mDesTextSize = a.getDimensionPixelSize(attr, (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,14,getResources().getDisplayMetrics()));
case R.styleable.QingtingView1_ImageRes:
mDrawable = a.getDrawable(attr);
}
}
a.recycle();
init();
}
这里我们只贴有 style的这个构造函数。
<span style="font-size:18px;"> private void init() {
mPaint = new Paint();
mTitleTextSize = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,16,getResources().getDisplayMetrics());
mDesTextSize = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,14,getResources().getDisplayMetrics());
mDrawablePadding = UIUtils.dip2px(getContext(),10);
mHeight = UIUtils.dip2px(getContext(), 80);
}</span>
就可以在 java代码里面获得Dp值。
public static int dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
在OnMeasure 方法里面。我们使用默认的width。和写死的height。其中width需要进一步处理。这里只是一个demo。要拿代码用到项目里面的请注意这个东西
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
setMeasuredDimension(width, mHeight);
}
最后是大头 Ondraw方法。代码较为简单。里面hardCode较多。在这里就不一行行的加奇葩的注释了。有问题可以在评论里面问。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float textStartX = 0;
if (null == mDrawable || null == mTitle || null == mDes)
return;
if (mDrawable.getIntrinsicHeight() != 0 && mDrawable.getIntrinsicWidth() != 0) {
int drawLength = mHeight - getPaddingBottom(); //由于是正方形的按照其高度进行剪切作为边长
mDrawable.setBounds(getPaddingLeft(), getPaddingTop(),drawLength,drawLength);
mDrawable.draw(canvas);
textStartX = drawLength + mDrawablePadding;
}
//标题
mPaint.setColor(Color.BLACK);
mPaint.setTextSize(mTitleTextSize);
Rect titleBound = new Rect();
mPaint.getTextBounds(mTitle, 0, mTitle.length(), titleBound);
canvas.drawText(mTitle, textStartX, (titleBound.height() + getPaddingTop()), mPaint);
//说明
int gap = UIUtils.dip2px(getContext(),10);
mPaint.setColor(Color.argb(255, 150, 150, 150));
mPaint.setTextSize(mDesTextSize);
Rect desBound = new Rect();
mPaint.getTextBounds(mDes, 0, mDes.length(), desBound);
canvas.drawText(mDes, textStartX, titleBound.height()
+ desBound.height() + gap + getPaddingTop(), mPaint);
if (mIsNeedTimeStamp) {
//时间戳
Rect timeBound = new Rect();
mPaint.setTextSize(UIUtils.dip2px(getContext(), 11));
mPaint.getTextBounds(mDes, 0, mDes.length(), timeBound);
canvas.drawText(TimeUtils.getStandarlizdTime(getContext(), mTimeStamp)
, getWidth() - timeBound.width(), getHeight() - getPaddingBottom(), mPaint);
}
if (mIsNeedStar) {
//画出star
if (mScore > 0) {
int starFullNum = mScore / 2;
int starhalfNum = mScore % 2;
int starEmptyNum = 5 - starFullNum - starhalfNum;
int starDrawX = (int) textStartX;
for (int count = 0; count < 5; count++) {
Drawable drawableStar;
if (starFullNum > count)
drawableStar = getResources().getDrawable(R.drawable.ic_star_full);
else if (starhalfNum != 0 && mScore >= count * 2)
drawableStar = getResources().getDrawable(R.drawable.ic_star_half);
else
drawableStar = getResources().getDrawable(R.drawable.ic_star_empty);
drawableStar.setBounds(starDrawX, getHeight() - (drawableStar.getIntrinsicHeight() / 3) - getPaddingBottom(),
starDrawX + (drawableStar.getIntrinsicWidth()) / 3, getHeight() - getPaddingBottom());
drawableStar.draw(canvas);
Log.d(TAG, "height: " + drawableStar.getIntrinsicHeight() + "width: " + drawableStar.getIntrinsicWidth());
starDrawX += (drawableStar.getIntrinsicWidth()) / 3 + UIUtils.dip2px(getContext(), 2); //间隔5dp
}
}
}
}
Github 地址。
https://github.com/WalkerLiuFei/QingTingFMView