这里我整理了几个大神的技术博文,结合着来自慕课网的代码,梳理一下自定义view要做的几个步骤。
1.在value中建立一个attr.xml,再声明几个属性:
/**
* 构造并初始化view的属性数据
*
* @param context
* @param attrs
* @param defStyleAttr
*/
public ChangeColorIconWithText(Context context, AttributeSet attrs,
int defStyleAttr)
{
super(context, attrs, defStyleAttr);
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.ChangeColorIconWithText);
//获得a中的view属性的个数
int n = a.getIndexCount();
for (int i = 0; i < n; i++)
{
//通过下标获得view属性的id
int attr = a.getIndex(i);
switch (attr)
{
//获得子view的数据,并赋值到全局变量
case R.styleable.ChangeColorIconWithText_icon:
BitmapDrawable drawable = (BitmapDrawable) a.getDrawable(attr);
mIconBitmap = drawable.getBitmap();
break;
case R.styleable.ChangeColorIconWithText_color:
mColor = a.getColor(attr, 0xFF45C01A);
break;
case R.styleable.ChangeColorIconWithText_text:
mText = a.getString(attr);
break;
case R.styleable.ChangeColorIconWithText_text_size:
mTextSize = (int) a.getDimension(attr, TypedValue
.applyDimension(TypedValue.COMPLEX_UNIT_SP, 12,
getResources().getDisplayMetrics()));
break;
}
}
//回收
a.recycle();
//初始化控件
mTextBound = new Rect();
mTextPaint = new Paint();
mTextPaint.setTextSize(mTextSize);
mTextPaint.setColor(0Xff555555);
//获得文本绘制区域
mTextPaint.getTextBounds(mText, 0, mText.length(), mTextBound);
}
//绘制布局的大小,必须实现的方法
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int iconWidth = Math.min(getMeasuredWidth() - getPaddingLeft()
- getPaddingRight(), getMeasuredHeight() - getPaddingTop()
- getPaddingBottom() - mTextBound.height());
int left = getMeasuredWidth() / 2 - iconWidth / 2;
int top = getMeasuredHeight() / 2 - (mTextBound.height() + iconWidth)
/ 2;
//确定icon的区域
mIconRect = new Rect(left, top, left + iconWidth, top + iconWidth);
}
@Override
protected void onDraw(Canvas canvas)
{
//绘制大小为mIcomRect的图片数据mIcomBitmap
canvas.drawBitmap(mIconBitmap, null, mIconRect, null);
int alpha = (int) Math.ceil(155 * mAlpha);
// 设置icon的颜色
setupTargetBitmap(alpha);
// 设置字体
drawSourceText(canvas, alpha);
drawTargetText(canvas, alpha);
canvas.drawBitmap(mBitmap, 0, 0, null);
}
/**
* 绘制字体
*
* @param canvas
* @param alpha
*/
private void drawTargetText(Canvas canvas, int alpha)
{
mTextPaint.setColor(mColor);
mTextPaint.setAlpha(alpha);
int x = getMeasuredWidth() / 2 - mTextBound.width() / 2;
int y = mIconRect.bottom + mTextBound.height();
//绘制文本,mTextPaint为文本绘制区域
canvas.drawText(mText, x, y, mTextPaint);
}
/**
* 绘制颜色变换的字体
*
* @param canvas
* @param alpha
*/
private void drawSourceText(Canvas canvas, int alpha)
{
mTextPaint.setColor(0xff333333);
mTextPaint.setAlpha(155 - alpha);
int x = getMeasuredWidth() / 2 - mTextBound.width() / 2;
int y = mIconRect.bottom + mTextBound.height();
canvas.drawText(mText, x, y, mTextPaint);
}
/**
* 绘制颜色可以变换的icon
*/
private void setupTargetBitmap(int alpha)
{
mBitmap = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(),
Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
mPaint = new Paint();
mPaint.setColor(mColor);
//用来防止边缘的锯齿
mPaint.setAntiAlias(true);
//防抖动
mPaint.setDither(true);
mPaint.setAlpha(alpha);
mCanvas.drawRect(mIconRect, mPaint);
//设置图像的混合模式
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
mPaint.setAlpha(155);
mCanvas.drawBitmap(mIconBitmap, null, mIconRect, mPaint);
}
/**
* 设置icon透明度
*/
public void setIconAlpha(float alpha)
{
this.mAlpha = alpha;
invalidateView();
}
/**
* 重绘
*/
private void invalidateView()
{
//判断是否在UI主线程
if (Looper.getMainLooper() == Looper.myLooper())
{
invalidate();//重绘view
} else
{
postInvalidate();//提交重绘view
}
}
private void initView()
{
mViewPager = (ViewPager) findViewById(R.id.id_viewpager);
ChangeColorIconWithText one = (ChangeColorIconWithText) findViewById(R.id.id_indicator_one);
mTabIndicators.add(one);
ChangeColorIconWithText two = (ChangeColorIconWithText) findViewById(R.id.id_indicator_two);
mTabIndicators.add(two);
ChangeColorIconWithText three = (ChangeColorIconWithText) findViewById(R.id.id_indicator_three);
mTabIndicators.add(three);
ChangeColorIconWithText four = (ChangeColorIconWithText) findViewById(R.id.id_indicator_four);
mTabIndicators.add(four);
one.setOnClickListener(this);
two.setOnClickListener(this);
three.setOnClickListener(this);
four.setOnClickListener(this);
one.setIconAlpha(1.0f);
}
private void clickTab(View v)
{
resetOtherTabs();
switch (v.getId())
{
case R.id.id_indicator_one:
mTabIndicators.get(0).setIconAlpha(1.0f);
mViewPager.setCurrentItem(0, false);
break;
case R.id.id_indicator_two:
mTabIndicators.get(1).setIconAlpha(1.0f);
mViewPager.setCurrentItem(1, false);
break;
case R.id.id_indicator_three:
mTabIndicators.get(2).setIconAlpha(1.0f);
mViewPager.setCurrentItem(2, false);
break;
case R.id.id_indicator_four:
mTabIndicators.get(3).setIconAlpha(1.0f);
mViewPager.setCurrentItem(3, false);
break;
}
}
@Override
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels)
{
// Log.e("TAG", "position = " + position + " ,positionOffset = "
// + positionOffset);
if (positionOffset > 0)
{
ChangeColorIconWithText left = mTabIndicators.get(position);
ChangeColorIconWithText right = mTabIndicators.get(position + 1);
left.setIconAlpha(1 - positionOffset);
right.setIconAlpha(positionOffset);
}
}
/**
* 绘制颜色可以变换的icon
*/
private void setupTargetBitmap(int alpha)
{
mBitmap = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(),
Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
mPaint = new Paint();
mPaint.setColor(mColor);
//用来防止边缘的锯齿
mPaint.setAntiAlias(true);
//防抖动
mPaint.setDither(true);
mPaint.setAlpha(alpha);
mCanvas.drawRect(mIconRect, mPaint);
//设置图像的混合模式
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
mPaint.setAlpha(155);
mCanvas.drawBitmap(mIconBitmap, null, mIconRect, mPaint);
}
① 当我们用Canvas绘制位图的时候,如果对位图进行了选择,则位图会出现锯齿。
② 在用View的RotateAnimation做动画时候,如果View当中包含有大量的图形,也会出现锯齿。我们分别以这两种情况加以考虑。
◆ 用Canvas绘制位的的情况。在用Canvas绘制位图时,一般地,我们使用drawBitmap函数家族,在这些函数中,都有一个Paint参数,要做到防止锯齿,我们就要使用到这个参数。如下:首先在你的构造函数中,需要创建一个Paint。 Paint mPaint = new Paint(); 然后,您需要设置两个参数: 1)mPaint.setAntiAlias(); 2)mPaint.setBitmapFilter(true)。第一个函数是用来防止边缘的锯齿,第二个函数是用来对位图进行滤波处理。最后,在画图的时候,调用drawBitmap函数,只需要将整个Paint传入即可。
◆ 有时候,当你做RotateAnimation时,你会发现,讨厌的锯齿又出现了。这个时候,由于你不能控制位图的绘制,只能用其他方法来实现防止锯齿。另外,如果你画的位图很多。不想每个位图的绘制都传入一个Paint。还有的时候,你不可能控制每个窗口的绘制的时候,您就需要用下面的方法来处理——对整个Canvas进行处理。 1)在您的构造函数中,创建一个Paint滤波器。 PaintFlagsDrawFilter mSetfil = new PaintFlagsDrawFilter(0, Paint.FILTER_BITMAP_FLAG);第一个参数是你要清除的标志位,第二个参数是你要设置的标志位。此处设置为对位图进行滤波。 2)当你在画图的时候,如果是View则在onDraw当中,如果是ViewGroup则在dispatchDraw中调用如下函数。 canvas.setDrawFilter( mSetfil );
★ 最后,另外,在Drawable类及其子类中,也有函数setFilterBitmap可以用来对Bitmap进行滤波处理,这样,当你选择Drawable时,会有抗锯齿的效果。(以上是来自转载博文。)
void setARGB(int a, int r, int g, int b) 设置Paint对象颜色,参数一为alpha透明通道
void setAlpha(int a) 设置alpha不透明度,范围为0~255
void setAntiAlias(boolean aa) //是否抗锯齿
void setColor(int color) //设置颜色,这里Android内部定义的有Color类包含了一些常见颜色定义
.
void setFakeBoldText(boolean fakeBoldText) //设置伪粗体文本
void setLinearText(boolean linearText) //设置线性文本
PathEffect setPathEffect(PathEffect effect) //设置路径效果
Rasterizer setRasterizer(Rasterizer rasterizer) //设置光栅化
Shader setShader(Shader shader) //设置阴影
void setTextAlign(Paint.Align align) //设置文本对齐
void setTextScaleX(float scaleX) //设置文本缩放倍数,1.0f为原始
void setTextSize(float textSize) //设置字体大小
Typeface setTypeface(Typeface typeface) //设置字体,Typeface包含了字体的类型,粗细,还有倾斜、颜色等。
mPaint.setXfermode( new PorterDuffXfermode(PorterDuff.Mode.SCREEN));
Canvas canvas = new Canvas(Src);
paint.setXfermode( new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(Dst, 0f, 0f, paint);