标签:
<?xml version="1.0" encoding="utf-8"?> <resources> <!--CustomTitleView--> <attr name="titleText" format="string" /> <attr name="titleTextColor" format="color" /> <attr name="titleTextSize" format="dimension" /> <declare-styleable name="CustomTitleView"> <attr name="titleText" /> <attr name="titleTextColor" /> <attr name="titleTextSize" /> </declare-styleable> </resources>
<!--属性值具体意义详述: reference:参考某一资源ID color:颜色值 boolean:布尔值 dimension:尺寸值 float:浮点值 integer:整型值 string:字符串 fraction:百分数 enum:枚举值 flag:位或运算 多类型: <declare-styleable name = "名称"> <attr name = "background" format = "reference|color" /> </declare-styleable> -->
/** * 文本 */ private String mTitleText; /** * 文本的颜色 */ private int mTitleTextColor; /** * 文本的大小 */ private int mTitleTextSize; /** * 绘制时控制文本绘制的范围 */ private Rect mBound; /** * 画笔 */ private Paint mPaint; /** * 构造方法 * * @param context * @param attrs */ public CustomTitleView(Context context, AttributeSet attrs) { this(context, attrs, 0); } /** * 构造方法 * * @param context */ public CustomTitleView(Context context) { this(context, null); } /** * 获得我自定义的样式属性 * * @param context * @param attrs * @param defStyle */ public CustomTitleView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); /** * 添加事件【<span style="color:#333399;">第五步时,把这一块代码加入</span>】 */ this.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mTitleText = randomText(); postInvalidate(); } }); /** * 获得我们所定义的自定义样式属性 */ TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomTitleView, defStyle, 0); int n = a.getIndexCount(); for (int i = 0; i < n; i++) { int attr = a.getIndex(i); switch (attr) { case R.styleable.CustomTitleView_titleText: mTitleText = a.getString(attr); break; case R.styleable.CustomTitleView_titleTextColor: // 默认颜色设置为黑色 mTitleTextColor = a.getColor(attr, Color.BLACK); break; case R.styleable.CustomTitleView_titleTextSize: // 默认设置为16sp,TypeValue也可以把sp转化为px mTitleTextSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics())); break; } } a.recycle(); /** * 获得绘制文本的宽和高 */ mPaint = new Paint(); mPaint.setTextSize(mTitleTextSize); mPaint.setColor(mTitleTextColor); mBound = new Rect(); mPaint.getTextBounds(mTitleText, 0, mTitleText.length(), mBound); }
@Override protected void onDraw(Canvas canvas) { mPaint.setColor(Color.YELLOW); canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint); mPaint.setColor(mTitleTextColor); canvas.drawText(mTitleText, getWidth() / 2 - mBound.width() / 2, getHeight() / 2 + mBound.height() / 2, mPaint); }
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { /** * 1,不重写该方法,系统默认填充父窗体 */ // super.onMeasure(widthMeasureSpec, heightMeasureSpec); /** * 2, 重写当前方法 */ int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); int width; int height; /** * 宽度获取 */ if (widthMode == MeasureSpec.EXACTLY) { width = widthSize; } else { mPaint.setTextSize(mTitleTextSize); mPaint.getTextBounds(mTitleText, 0, mTitleText.length(), mBound); float textWidth = mBound.width(); int desired = (int) (getPaddingLeft() + textWidth + getPaddingRight()); width = desired; } /** * 高度获取 */ if (heightMode == MeasureSpec.EXACTLY) { height = heightSize; } else { mPaint.setTextSize(mTitleTextSize); mPaint.getTextBounds(mTitleText, 0, mTitleText.length(), mBound); float textHeight = mBound.height(); int desired = (int) (getPaddingTop() + textHeight + getPaddingBottom()); height = desired; } setMeasuredDimension(width, height); }
/** * 生成随机文字【也可以实现其他的事件,管理控件属性】 * * @return */ private String randomText() { Random random = new Random(); Set<Integer> set = new HashSet<Integer>(); while (set.size() < 4) { int randomInt = random.nextInt(10); set.add(randomInt); } StringBuffer sb = new StringBuffer(); for (Integer i : set) { sb.append("" + i); } return sb.toString(); }
二、自定义控件(二) --- 属性TextView联合图片
<!--CustomImageView--> <attr name="image" format="reference" /> <attr name="imageScaleType"> <enum name="fillXY" value="0" /> <enum name="center" value="1" /> </attr> <declare-styleable name="CustomImageView"> <attr name="titleText" /> <attr name="titleTextSize" /> <attr name="titleTextColor" /> <attr name="image" /> <attr name="imageScaleType" /> </declare-styleable>
/** * 类说明:带图片说明的ImageView控件 * 作者:vision * 时间:2016/7/15 */ public class CustomImageView extends View { /** * 标识图片当前缩放模式 */ private static final int IMAGE_SCALE_FITXY = 0; /** * 文本 */ private String mTitle; /** * 文本的颜色 */ private int mTextColor; /** * 文本的大小 */ private int mTextSize; /** * 缩放参数 */ private int mImageScale; /** * 绘制时控制文本绘制的范围 */ private Rect mTextBound; /** * 绘制整体的范围 */ private Rect rect; /** * 画笔 */ private Paint mPaint; /** * 图像内容 */ private Bitmap mImage; /** * 控件宽度 */ private int mWidth; /** * 控件高度 */ private int mHeight; /** * 响应事件监听器 */ private CustomImageViewClickListener listener; /** * 构造方法 * * @param context * @param attrs */ public CustomImageView(Context context, AttributeSet attrs) { this(context, attrs, 0); } /** * 构造方法 * * @param context */ public CustomImageView(Context context) { this(context, null); } /** * 初始化所特有自定义类型 * * @param context * @param attrs * @param defStyle */ public CustomImageView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); this.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { if (listener != null) { listener.onCustomImageViewClickListener(view); } } }); TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomImageView, defStyle, 0); int n = a.getIndexCount(); for (int i = 0; i < n; i++) { int attr = a.getIndex(i); switch (attr) { case R.styleable.CustomImageView_image: mImage = BitmapFactory.decodeResource(getResources(), a.getResourceId(attr, 0)); break; case R.styleable.CustomImageView_imageScaleType: mImageScale = a.getInt(attr, 0); break; case R.styleable.CustomImageView_titleText: mTitle = a.getString(attr); break; case R.styleable.CustomImageView_titleTextColor: mTextColor = a.getColor(attr, Color.BLACK); break; case R.styleable.CustomImageView_titleTextSize: mTextSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics())); break; } } a.recycle(); rect = new Rect(); mPaint = new Paint(); mTextBound = new Rect(); mPaint.setTextSize(mTextSize); // 计算了描绘字体需要的范围 mPaint.getTextBounds(mTitle, 0, mTitle.length(), mTextBound); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // super.onMeasure(widthMeasureSpec, heightMeasureSpec); /** * 设置宽度 */ int specMode = MeasureSpec.getMode(widthMeasureSpec); int specSize = MeasureSpec.getSize(widthMeasureSpec); if (specMode == MeasureSpec.EXACTLY) {// match_parent , accurate Log.e("xxx", "EXACTLY"); mWidth = specSize; } else { // 由图片决定的宽 int desireByImg = getPaddingLeft() + getPaddingRight() + mImage.getWidth(); // 由字体决定的宽 int desireByTitle = getPaddingLeft() + getPaddingRight() + mTextBound.width(); if (specMode == MeasureSpec.AT_MOST) {// wrap_content int desire = Math.max(desireByImg, desireByTitle); mWidth = Math.min(desire, specSize); Log.e("xxx", "AT_MOST"); } } /*** * 设置高度 */ specMode = MeasureSpec.getMode(heightMeasureSpec); specSize = MeasureSpec.getSize(heightMeasureSpec); if (specMode == MeasureSpec.EXACTLY) {// match_parent , accurate mHeight = specSize; } else { int desire = getPaddingTop() + getPaddingBottom() + mImage.getHeight() + mTextBound.height(); if (specMode == MeasureSpec.AT_MOST) {// wrap_content mHeight = Math.min(desire, specSize); } } setMeasuredDimension(mWidth, mHeight); } @Override protected void onDraw(Canvas canvas) { // super.onDraw(canvas); /** * 边框 */ mPaint.setStrokeWidth(4); mPaint.setStyle(Paint.Style.STROKE); mPaint.setColor(Color.CYAN); canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint); rect.left = getPaddingLeft(); rect.right = mWidth - getPaddingRight(); rect.top = getPaddingTop(); rect.bottom = mHeight - getPaddingBottom(); mPaint.setColor(mTextColor); mPaint.setStyle(Paint.Style.FILL); /** * 当前设置的宽度小于字体需要的宽度,将字体改为xxx... */ if (mTextBound.width() > mWidth) { TextPaint paint = new TextPaint(mPaint); String msg = TextUtils.ellipsize(mTitle, paint, (float) mWidth - getPaddingLeft() - getPaddingRight(), TextUtils.TruncateAt.END).toString(); canvas.drawText(msg, getPaddingLeft(), mHeight - getPaddingBottom(), mPaint); } else { //正常情况,将字体居中 canvas.drawText(mTitle, mWidth / 2 - mTextBound.width() * 1.0f / 2, mHeight - getPaddingBottom(), mPaint); } //取消使用掉的快 rect.bottom -= mTextBound.height(); if (mImageScale == IMAGE_SCALE_FITXY) { canvas.drawBitmap(mImage, null, rect, mPaint); } else { //计算居中的矩形范围 rect.left = mWidth / 2 - mImage.getWidth() / 2; rect.right = mWidth / 2 + mImage.getWidth() / 2; rect.top = (mHeight - mTextBound.height()) / 2 - mImage.getHeight() / 2; rect.bottom = (mHeight - mTextBound.height()) / 2 + mImage.getHeight() / 2; canvas.drawBitmap(mImage, null, rect, mPaint); } } /** * 设置监听器 * * @param listener */ public void setListener(CustomImageViewClickListener listener) { this.listener = listener; } public interface CustomImageViewClickListener { void onCustomImageViewClickListener(View v); } }
<future.com.selfdefineviewfirst.view.CustomTitleView android:id="@+id/text_self_define" android:layout_width="wrap_content" android:layout_height="wrap_content" app:titleText="自定义控件属性:标题文字" app:titleTextColor="@color/green" app:titleTextSize="18sp" />
<future.com.selfdefineviewfirst.view.CustomImageView android:id="@+id/pengyuyan1" android:layout_width="150dp" android:layout_height="wrap_content" selfde:image="@mipmap/a7" selfde:imageScaleType="center" selfde:titleText="彭于晏最棒最帅最好的潜力股" selfde:titleTextColor="#0000ff" selfde:titleTextSize="30sp" />
public class MainActivity extends AppCompatActivity implements CustomView.CustomListener { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ((CustomView) this.findViewById(R.id.custom1)).setCustomListener(this); } @Override public void onCuscomClick(View v, int custom_id) { switch (custom_id) { case 1: Toast.makeText(this, "你点我干嘛?!", Toast.LENGTH_LONG).show(); break; default: break; } }
/** * 类说明:CustomImageView 展示页面 * 增加:控件点击事件 * <p/> * 作者:vision * 时间:2016/7/15 */ public class CustomImageViewActivity extends Activity implements CustomImageView.CustomImageViewClickListener { /** * 第一个控件 */ private CustomImageView pengyuyan1; /** * 第二个控件 */ private CustomImageView pengyuyan2; /** * 第三个控件 */ private CustomImageView pengyuyan3; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_custom_image_view); pengyuyan1 = (CustomImageView) findViewById(R.id.pengyuyan1); pengyuyan2 = (CustomImageView) findViewById(R.id.pengyuyan2); pengyuyan3 = (CustomImageView) findViewById(R.id.pengyuyan3); pengyuyan1.setListener(this); pengyuyan2.setListener(this); pengyuyan3.setListener(this); } @Override public void onCustomImageViewClickListener(View v) { switch (v.getId()) { case R.id.pengyuyan1: Toast.makeText(this, "帅哥彭于晏1", Toast.LENGTH_LONG).show(); break; case R.id.pengyuyan2: Toast.makeText(this, "德艺双馨彭于晏2", Toast.LENGTH_LONG).show(); break; case R.id.pengyuyan3: Toast.makeText(this, "超越自己彭于晏3", Toast.LENGTH_LONG).show(); break; } } }
Android自定义控件 ----- 基本绘制流程,简单控件的实现
标签:
原文地址:http://blog.csdn.net/u013205623/article/details/51939192