Android TV开发之----圆角布局控件实现

一开始是这样的,热门的控件(LabeView),是三角形的,
图片是圆角的.
然后下面的TextView带背景颜色的是长方形的。
都不是圆角.
 
 
 【如何绘制真正的圆角矩形控件?】
 
    一般 ImageView 使用 OnDraw,虽然能弄成圆角,比如在 FrameLayout( 就是继承ViewGroup的控件)下,它显示是正常的圆角。但是,如果再放一个文本(设置背景颜色)或者按钮,layout_width 占满 FrameLayout控件的话,你就发现,只是ImageView圆角了,Button或者文本 超出了ImageView的圆角,FrameLayout 并不是真正的圆角.
    这样看来,这并不是我想要的效果。
    继续分析源码.
    
【绘制过程分析】
 
ImageView.java
 
@Override 
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas); 
    if (mDrawable == null) {
        return; // couldn't resolve the URI
    }
    ... ...
    mDrawable.draw(canvas);
    ... ...
}
 
如果你使用 setBackgroundDrawable 设置ImageView,那么mDrawable就是null.
setBackgroundDrawable 是设置的背景,具体看 View.java.
 
public ImageView(Context context, AttributeSet attrs, int defStyle) {
    ... ...
    Drawable d = a.getDrawable(com.android.internal.R.styleable.ImageView_src);
    if (d != null) {
        setImageDrawable(d);
    ... ...
}
以上代码发现 src="@dra..."
如果你使用 setImageDrawable 设置ImageView,那么就
将 mDrawable 绘制出来, 是我们设置ImageView 图片或者资源图片时候赋的.
 
从上面的代码也分析的出来,ImageView的背景和src还有有区别的噢.
有何种区别,继续看看源码.
 
FrameLayout.java
 
FrameLayout 并没有重写 onDraw 函数, 看看继承的ViewGroup.
 
public void setWillNotDraw(boolean willNotDraw) {
    setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK);
}
 
ViewGroup.java
 
ViewGroup 也没有重写 onDraw函数,再看看继承的View.
 
View.java
 
View 找到了 onDraw 函数.
protected void onDraw(Canvas canvas) {
}
不过它只是一个空函数,什么事情都没有做.
 
来找找看,谁调用了 onDraw吧 ,不错就是 draw 函数.
 
这是draw函数给出的注释。
 
       /*
         * Draw traversal performs several drawing steps which must be executed
         * in the appropriate order:
         *
         *      1. Draw the background
         *      2. If necessary, save the canvas' layers to prepare for fading
         *      3. Draw view's content
         *      4. Draw children
         *      5. If necessary, draw the fading edges and restore layers : 处理渐变
         *      6. Draw decorations (scrollbars for instance)
         */
 
public void  draw(Canvas canvas) {
    // Step 1, draw the background, if needed :  第一步,绘制背景.
    ... ...
    if (! dirtyOpaque) { // (A4)
        final Drawable background = mBackground; // (A5)
    ... ...
    // Step 3, draw the content:绘制本身的内容(一般继承viewGroup无).
    if (! dirtyOpaqueonDraw(canvas);
 
    // Step 4, draw the children:绘制子控件.
     dispatchDraw(canvas);
    // Step 5, draw the fade effect and restore layers:渐变
    ... ...
    // Step 6, draw decorations (scrollbars):绘制滚动条.
     onDrawScrollBars(canvas);
}
 
如果不需要绘制渐变,则跳过第2和5步。
 
A4: dirtyOpaque 表示 dirty 区是否是不透明 为 True, 透明为 false【一般Android的几乎都是透明的,都为false】.
        如果View系统不支持Alpha通道,不需要绘制背景,因为视图本身会占满整个区域,背景会完全被挡住。
A5 :mBackground 就是设置背景时候传入的.
 
dispatchDraw 内部绘制子控件,也是调用的childView. draw(... ...
 
------------------
 
通过上面的分析,我们大概知道了流程。
android是如何绘制控件,以及子控件出来的。
我们知道 Path 这个函数.
然后就可以开始着手写代码了.
 
-------------------
 
为了实现真正的圆角,我重写了 draw.
 
开始使用clippath,会有锯齿问题.
后来又改了一种方法。
 
mShapePaint = new Paint();
        mShapePaint.setColor(Color.WHITE);
        mShapePaint.setAntiAlias(true);
        mShapePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
 
@Override
    public void draw(Canvas canvas) {
      if (mIsDrawShape && isDrawShapeRadiusRect(mRadiusRect)) {
            drawShapePathCanvas(canvas);
        } else {
            super.draw(canvas);
        }
    }
 
private void drawShapePath(Canvas canvas) {
        int width = getWidth();
        int height = getHeight();
        int count = canvas.save();
        // 绘制圆角
        Canvas shapeCanvas = canvas; 
        int count2 = shapeCanvas.saveLayer(0, 0, width, height, null, Canvas.ALL_SAVE_FLAG);
        Path path = DrawUtils.addRoundPath3(width, height, mRadius);
        super.draw(shapeCanvas);
        shapeCanvas.drawPath(path, mShapePaint);
        shapeCanvas.restoreToCount(count2);
        canvas.restoreToCount(count);
 
    }
 
 
那么 super.draw 绘制的控件内容,区域显示了.
如果你的区域是一个圆角的矩形,哈哈哈.
现在无论放什么控件,Framelayout都是圆角的,OK了.
 
 
下载源码 查看 ReflectItemView.java吧.
 
最终的效果。
 
 
    
    

转载于:https://www.cnblogs.com/androidtvdev/p/5391297.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值