使用xml实现边框

原来使用带边框的TextView时一般都是用XML定义来完成,在drawable目录中定义如下所示的xml文件:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 点击状态下按钮背景样式 -->
<item android:state_pressed="true">
<shape android:shape="rectangle">
<corners android:radius="2dp"/>
<solid android:color="@android:color/transparent"/>
<stroke android:width="1dp"
android:color="#ff48beab"/>
</shape>
</item>
<!-- 正常点击状态下按钮背景样式 -->
<item android:state_pressed="false">
<shape android:shape="rectangle">
<corners android:radius="2dp"/>
<solid android:color="@android:color/transparent"/>
<stroke android:width="1dp"
android:color="#ff48baab"/>
</shape>
</item>
</selector>

这样可以实现圆角边框,但颜色是固定的,如果需要在不同位置放置不同的TextView(比如多种颜色的按钮),那么就要定义多个颜色不同的XML文件。

自定义带边框的TextView

最近在做项目时遇到多种颜色的标签需求,如果还是按照上面的做法,那么需要多套XML文件配合,于是我想了一下,能不能自定义一个控件,让边框颜色在使用时指定。

在项目的设计图中主要是用于一些标签,如下图所示:

接下来我就尝试了一下,发现是可行的,于是就有了下面这个自定义,在个人项目中基本够用。

这个控件是继承自TextView的,只是在onDraw方法中画了一个边框,并设计了几个自定义属性用来更灵活地控制控件。

自定义属性如下:

<declare-styleable name="BorderTextView">
<attr name="strokeWidth" format="dimension"/>
<attr name="cornerRadius" format="dimension"/>
<attr name="strokeColor" format="color"/>
<attr name="followTextColor" format="boolean"/>
</declare-styleable>

这几个属性简要解释如下:

  • strokeWidth 
    边框的宽度,默认为1dp
  • cornerRadius 
    圆角半径,默认为2dp
  • strokeColor 
    边框颜色,默认是没有边框即颜色为Color.TRANSPARENT
  • followTextColor 
    边框是否跟随文字颜色,默认是true

自定义控件代码(BorderTextView ):

package com.witmoon.eab.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.widget.TextView; import com.witmoon.eab.R; /**
* 用于作为标签显示的TextView
* 边框默认与文字颜色一致
* Created by chuxin on 2015/9/11.
*/
public class BorderTextView extends TextView { public static final float DEFAULT_STROKE_WIDTH = 1.0f; // 默认边框宽度, 1dp
public static final float DEFAULT_CORNER_RADIUS = 2.0f; // 默认圆角半径, 2dp
public static final float DEFAULT_LR_PADDING = 6f; // 默认左右内边距
public static final float DEFAULT_TB_PADDING = 2f; // 默认上下内边距 private int strokeWidth; // 边框线宽
private int strokeColor; // 边框颜色
private int cornerRadius; // 圆角半径
private boolean mFollowTextColor; // 边框颜色是否跟随文字颜色 private Paint mPaint = new Paint(); // 画边框所使用画笔对象
private RectF mRectF; // 画边框要使用的矩形 public BorderTextView(Context context) {
this(context, null);
} public BorderTextView(Context context, AttributeSet attrs) {
this(context, attrs, );
} public BorderTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr); // 将DIP单位默认值转为PX
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
strokeWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
DEFAULT_STROKE_WIDTH, displayMetrics);
cornerRadius = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
DEFAULT_CORNER_RADIUS, displayMetrics); // 读取属性值
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.BorderTextView);
strokeWidth = ta.getDimensionPixelSize(R.styleable.BorderTextView_strokeWidth, strokeWidth);
cornerRadius = ta.getDimensionPixelSize(R.styleable.BorderTextView_cornerRadius, cornerRadius);
strokeColor = ta.getColor(R.styleable.BorderTextView_strokeColor, Color.TRANSPARENT);
mFollowTextColor = ta.getBoolean(R.styleable.BorderTextView_followTextColor, true);
ta.recycle(); mRectF = new RectF(); // 边框默认颜色与文字颜色一致
// if (strokeColor == Color.TRANSPARENT)
// strokeColor = getCurrentTextColor(); // 如果使用时没有设置内边距, 设置默认边距
int paddingLeft = getPaddingLeft() == ? (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, DEFAULT_LR_PADDING, displayMetrics) : getPaddingLeft();
int paddingRight = getPaddingRight() == ? (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, DEFAULT_LR_PADDING,
displayMetrics) : getPaddingRight();
int paddingTop = getPaddingTop() == ? (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, DEFAULT_TB_PADDING, displayMetrics) : getPaddingTop();
int paddingBottom = getPaddingBottom() == ? (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, DEFAULT_TB_PADDING,
displayMetrics) : getPaddingBottom();
setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
} @Override
protected void onDraw(@NonNull Canvas canvas) {
super.onDraw(canvas); mPaint.setStyle(Paint.Style.STROKE); // 空心效果
mPaint.setAntiAlias(true); // 设置画笔为无锯齿
mPaint.setStrokeWidth(strokeWidth); // 线宽 // 设置边框线的颜色, 如果声明为边框跟随文字颜色且当前边框颜色与文字颜色不同时重新设置边框颜色
if (mFollowTextColor && strokeColor != getCurrentTextColor())
strokeColor = getCurrentTextColor();
mPaint.setColor(strokeColor); // 画空心圆角矩形
mRectF.left = mRectF.top = 0.5f * strokeWidth;
mRectF.right = getMeasuredWidth() - strokeWidth;
mRectF.bottom = getMeasuredHeight() - strokeWidth;
canvas.drawRoundRect(mRectF, cornerRadius, cornerRadius, mPaint);
}
}

代码中的注释也比较详细了,而且也非常简单,因此这里应该不需要赘述。唯一需要注意的是在画边框时使用的RectF尺寸,如果边框宽度较宽,由于Paint笔触是在边框中线为准,因此如果左上角指定为(0,0)话,会有一半边框宽度的线是画在不见区域的;这里指定左上角坐标为 0.5f * strokeWidth(即半个边框宽度)即可,右下角也需要作同样的考虑。

使用

自定义控件的使用就更简单了,这里我没有设置自定义属性,一切采用默认值:

<com.witmoon.eab.widget.BorderTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="身份验证"
android:textColor="@color/tag_text_blue"/>

展示效果如下图所示:

基本上满足要求。

作为按钮使用

在某些时候,我们可能会需要一些这种中间镂空的按钮,BorderTextView也可以用在这种情况下,下面是个例子。

首先在values目录中新建一个colors目录,在其中创建一个xml文件(button_text_color.xml),内容如下

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/secondary_text" android:state_pressed="true"/>
<item android:color="@color/hint_text" android:state_enabled="false"/>
<item android:color="@color/primary_text"/>
</selector>

其实是为按钮在不同状态下指定不同的颜色,以响应点击或禁用操作,增加用户体验。

<com.witmoon.eab.widget.BorderTextView
android:id="@+id/retrieve_check_code_again"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="6dp"
android:enabled="false"
android:textColor="@color/button_text_color"
android:paddingTop="6dp"
android:text="重新发送"/>

由于默认情况下边框是跟随文字颜色的,因此在被点击或者禁用时TextView会重新绘制,边框也随之改变颜色。

Android自定义控件 -- 带边框的TextView的更多相关文章

  1. 自定义控件 带描边的TextView

    使用 public class MainActivity extends Activity {     @Override     protected void onCreate(Bundle sav ...

  2. android自定义控件实例(Linearlayout组合TextView和ImageView)

    2013-12-18 11:25:22 转载自: http://www.open-open.com/lib/view/open1328836804515.html 很多时候android常用的控件不能 ...

  3. android基本控件学习-----TextView

    一.TextView的讲解 <实例一> <?xml version="1.0" encoding="utf-8"?> <Linea ...

  4. Android自定义控件之TextView

    转自:http://labs.easymobi.cn/?p=284 有时候Android自带的控件无法满足我们的某些要求,这时就需要我们自定义控件来实现这些功能.比如需要一个TextView里的字倾斜 ...

  5. android自定义控件实现TextView按下后字体颜色改变

    今天跟大家分享一下Android自定义控件入门,先介绍一个简单的效果TextView,按下改变字体颜色,后期慢慢扩展更强大的功能 直接看图片             第一张是按下后截的图,功能很简单, ...

  6. 解决android自带textview右侧文字不能对齐的问题

    package com.sixin.view; import android.content.Context; import android.graphics.Canvas; import andro ...

  7. Android GridView去除自带边框点击效果、去除右侧滚动条、禁止上下滑动

    一.去除自带边框点击效果: <com.example.gridview.MyGridView android:id="@+id/grid_upload_pictures" a ...

  8. Android ------------------ 带边框的圆角矩形

    <?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http:/ ...

  9. Android自定义控件View(三)组合控件

    不少人应该见过小米手机系统音量控制UI,一个圆形带动画效果的音量加减UI,效果很好看.它是怎么实现的呢?这篇博客来揭开它的神秘面纱.先上效果图 相信很多人都知道Android自定义控件的三种方式,An ...

随机推荐

  1. 10.18 NOIP2018提高组模拟题(二)

    大水题 1.咒语 (curse.pas/c/cpp) [题目描述] 亮亮梦到自己来到了魔法城堡,但一扇巨大的石门阻拦了他通向城堡内的路.正当他沮丧之际,突然发现门上有一处机关,机关上有一张很长的纸条. ...

  2. 「NOI.AC」Leaves 线段树合并

    题目描述 现在有一棵二叉树,所有非叶子节点都有两个孩子.在每个叶子节点上有一个权值(有\(n\)个叶子节点,满足这些权值为\(1\dots n\)的一个排列).可以任意交换每个非叶子节点的左右孩子. ...

  3. Vue中添加过渡效果

    最近在学习Vue这个框架,发现新的版本中,官网的文档里面说的过渡效果,如果直接粘贴官方的例子中的代码,发现并没有过渡的效果,经过反复测试之后终于知道怎么搞了,把测试的过程总结一下,以便以后回顾. 贴上 ...

  4. QueryTask,FindTask,IdentifyTask三种查询的区别

    1:QueryTask是一个进行空间和属性查询的功能类,它可以在某个地图服务的某个子图层内进行查询,顺便需要提一下的是,QueryTask进行查询的地图服务并不必项加载到Map中进行显示.QueryT ...

  5. Linux系统centos中sudo命令不能用----提升权限

    gyx is not in the sudoers file.  This incident will be reported. 1.切换到root用户 su ,如果想要切换回去 exit 2.添加s ...

  6. Python:raw_input 和 input用法

    转自:http://blog.csdn.net/kjing/article/details/7450146 Python input和raw_input的区别 使用input和raw_input都可以 ...

  7. [PowerShell]template engine

    今天讨论的是如何在Powershell里实现一个简单的Template Engine的功能. 假设模板文件的内容如下:template.tt hello $name welcome $company ...

  8. C语言的存储类别和动态内存分配

    存储类别分三大类: 静态存储类别 自动存储类别 动态分配内存 变量.对象--->内存管理 内存考虑效率(时间更短.空间更小) 作用域 链接.---->空间 存储器   ----->时 ...

  9. hdu3483 A Very Simple Problem 非线性递推方程2 矩阵快速幂

    题目传送门 题目描述:给出n,x,mod.求s[n]. s[n]=s[n-1]+(x^n)*(n^x)%mod; 思路:这道题是hdu5950的进阶版.大家可以看这篇博客hdu5950题解. 由于n很 ...

  10. CF 520 B. Two Buttons(bfs)

    /*题意:一个数,就是输入的第一个数,让它变成第二个数最少用几步.可以点红色按钮,蓝色按钮来改变数字,红色:*2,蓝色:-1,如果变成负数,就变成原来的数.CF 520 B. Two Buttons思 ...