Android 深入(一)- 自定义View之BottomTitleImageView
来源:互联网 发布:单片机串口通信程序 编辑:程序博客网 时间:2024/06/15 06:24
通过本文你可以了解到自定义View的知识,同时你可以学会如何写一个属于自己的View。同时希望能够通过这个例子重新学习下自定义View的知识。
Android 开发到一定程度的时候,可以独立开发一款App,一些基本的知识都有使用。这时候必须进行自我提高,深入的研究下Android的各个方面,不然也只能停留在初级程序员的层次,只能是一个码农啦!
自定义View是我们需要掌握的基本知识,在开发中一些需求使用系统内置的View不好实现,我们经常会自定义我们自己的View,同时在面试中经常被问到。下面我们就通过一个带有底部标题的自定义ImageView来学习下自定义View。
先看看效果图(效果就类似于有标题轮播图片的效果):
1.View的生命周期。
1)从图中我们View的整个生命周期,主要由三部分操作完成分别是measure()、layout()、draw(),作用如下:
- measure:计算视图的大小。
- layout:设置视图在屏幕中显示的位置。
- draw:绘制视图。其中onDraw()方法会花费大量时间,布局变化会重绘视图,所以在onDraw()中要避免对象分配。
2)invalidate() 和requsetLaytout()作用如下:
- invalidate():重新绘制view,执行draw()操作。
- requsetLaytout():重新请求绘制view,执行measure()和layout()过程,但不执行draw()操作。
2. 定义和加载自定义属性。
1)在values文件夹中定义属性文件attrs_wcircle_view.xml。
<resources> <declare-styleable name="WBottomTitleView"> <attr name="textString" format="string" /> <attr name="textDimension" format="dimension" /> <attr name="textColor" format="color" /> <attr name="mAlpha" format="integer" /> <attr name="mTextBgColor" format="color" /> <attr name="textDrawable" format="color|reference" /> </declare-styleable></resources>
2) 在自定义布局的构造方法中加载自定义属性,根据属性更新画笔。
public WBottomTitleView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(attrs, defStyle); } private void init(AttributeSet attrs, int defStyle) { //加载 attributes final TypedArray typedArray = getContext().obtainStyledAttributes( attrs, R.styleable.WBottomTitleView, defStyle, 0); mTextString = typedArray.getString( R.styleable.WBottomTitleView_textString); mTextColor = typedArray.getColor( R.styleable.WBottomTitleView_textColor, mTextColor); mTextDimension = typedArray.getDimension( R.styleable.WBottomTitleView_textDimension, mTextDimension); mAlpha = typedArray.getInt(R.styleable.WBottomTitleView_mAlpha, mAlpha); mTextBgColor = typedArray.getInt(R.styleable.WBottomTitleView_mTextBgColor, mTextBgColor); if (typedArray.hasValue(R.styleable.WBottomTitleView_textDrawable)) { mTextDrawable = typedArray.getDrawable( R.styleable.WBottomTitleView_textDrawable); mTextDrawable.setCallback(this); } typedArray.recycle(); mTextPaint = new TextPaint(); mTextPaint.setFlags(Paint.ANTI_ALIAS_FLAG); mTextPaint.setTextAlign(Paint.Align.LEFT); p = new Paint(); invalidateTextPaintAndMeasurements(); } //根据attributes更新TextPaint private void invalidateTextPaintAndMeasurements() { mTextPaint.setTextSize(mTextDimension); mTextPaint.setColor(mTextColor); if (TextUtils.isEmpty(mTextString)) { mTextString = ""; } Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics(); mTextHeight = fontMetrics.bottom; }
TypedArray是一个数组容器,用于存储加载的属性。记住:用完必须recycle(),不然会发生内存泄漏。
Paint.FontMetrics解析:
1)top是一行文字的上边界
2)ascent是文字可视区域的上边界
3)descent是文字可视区域的下边界
4)bottom是一行文字的下边界
5)leading是行与行之间的间距(通常为0,bottom与descent及top与ascent之间的间距足够间隔行行)
从上图中可以发现文字的可视区域在ascent与descent之间,top与bottom见的距离是整个文字所占空间的高度。
3. onDraw()绘制视图。
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); int paddingLeft = getPaddingLeft(); int paddingTop = getPaddingTop(); int paddingRight = getPaddingRight(); int paddingBottom = getPaddingBottom(); int contentWidth = getWidth() - paddingLeft - paddingRight; int contentHeight = getHeight() - paddingTop - paddingBottom; mTextPaintfontMetrics = mTextPaint.getFontMetrics(); p.setColor(mTextBgColor);// 设置灰色 p.setAlpha(mAlpha); p.setStyle(Paint.Style.FILL);//设置填满 canvas.drawRect(paddingLeft, contentHeight - (mTextPaintfontMetrics.bottom - mTextPaintfontMetrics.top), contentWidth, contentHeight, p);// 矩形 // Draw the text. canvas.drawText(mTextString, paddingLeft, paddingTop + (contentHeight - mTextHeight), mTextPaint); // Draw the text drawable on top of the text. if (mTextDrawable != null) { mTextDrawable.setBounds(paddingLeft, paddingTop, paddingLeft + contentWidth, paddingTop + contentHeight); mTextDrawable.draw(canvas); } }
4. 完整代码
package cn.studyou.myviewdeep.view;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.drawable.Drawable;import android.text.TextPaint;import android.text.TextUtils;import android.util.AttributeSet;import android.widget.ImageView;import cn.studyou.myviewdeep.R;/** * 基本功能:带有底部标题的ImageView * 创建:王杰 * 创建时间:2017-02-18 */public class WBottomTitleView extends ImageView { private String mTextString; private int mTextColor = Color.RED; private int mAlpha = 150; private float mTextDimension = 0; private Drawable mTextDrawable; private Paint p; private TextPaint mTextPaint; private float mTextHeight; private int mTextBgColor = Color.DKGRAY; private Paint.FontMetrics mTextPaintfontMetrics; public WBottomTitleView(Context context) { super(context); init(null, 0); } public WBottomTitleView(Context context, AttributeSet attrs) { super(context, attrs); init(attrs, 0); } public WBottomTitleView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(attrs, defStyle); } private void init(AttributeSet attrs, int defStyle) { //加载 attributes final TypedArray typedArray = getContext().obtainStyledAttributes( attrs, R.styleable.WBottomTitleView, defStyle, 0); mTextString = typedArray.getString( R.styleable.WBottomTitleView_textString); mTextColor = typedArray.getColor( R.styleable.WBottomTitleView_textColor, mTextColor); mTextDimension = typedArray.getDimension( R.styleable.WBottomTitleView_textDimension, mTextDimension); mAlpha = typedArray.getInt(R.styleable.WBottomTitleView_mAlpha, mAlpha); mTextBgColor = typedArray.getInt(R.styleable.WBottomTitleView_mTextBgColor, mTextBgColor); if (typedArray.hasValue(R.styleable.WBottomTitleView_textDrawable)) { mTextDrawable = typedArray.getDrawable( R.styleable.WBottomTitleView_textDrawable); mTextDrawable.setCallback(this); } typedArray.recycle(); mTextPaint = new TextPaint(); mTextPaint.setFlags(Paint.ANTI_ALIAS_FLAG); mTextPaint.setTextAlign(Paint.Align.LEFT); p = new Paint(); invalidateTextPaintAndMeasurements(); } //根据attributes更新TextPaint private void invalidateTextPaintAndMeasurements() { mTextPaint.setTextSize(mTextDimension); mTextPaint.setColor(mTextColor); if (TextUtils.isEmpty(mTextString)) { mTextString = ""; } Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics(); mTextHeight = fontMetrics.bottom; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); int paddingLeft = getPaddingLeft(); int paddingTop = getPaddingTop(); int paddingRight = getPaddingRight(); int paddingBottom = getPaddingBottom(); int contentWidth = getWidth() - paddingLeft - paddingRight; int contentHeight = getHeight() - paddingTop - paddingBottom; mTextPaintfontMetrics = mTextPaint.getFontMetrics(); p.setColor(mTextBgColor);// 设置灰色 p.setAlpha(mAlpha); p.setStyle(Paint.Style.FILL);//设置填满 canvas.drawRect(paddingLeft, contentHeight - (mTextPaintfontMetrics.bottom - mTextPaintfontMetrics.top), contentWidth, contentHeight, p);// 矩形 // Draw the text. canvas.drawText(mTextString, paddingLeft, paddingTop + (contentHeight - mTextHeight), mTextPaint); // Draw the text drawable on top of the text. if (mTextDrawable != null) { mTextDrawable.setBounds(paddingLeft, paddingTop, paddingLeft + contentWidth, paddingTop + contentHeight); mTextDrawable.draw(canvas); } } public String gettextString() { return mTextString; } public void setTextString(String textString) { mTextString = textString; invalidateTextPaintAndMeasurements(); } public int getTextColor() { return mTextColor; } public void setTextColor(int textColor) { mTextColor = textColor; invalidateTextPaintAndMeasurements(); } public float getTextDimension() { return mTextDimension; } public void setTextDimension(float textDimension) { mTextDimension = textDimension; invalidateTextPaintAndMeasurements(); } public Drawable getTextDrawable() { return mTextDrawable; } public void setTextDrawable(Drawable textDrawable) { mTextDrawable = textDrawable; } public int getmTextBgColor() { return mTextBgColor; } public void setmTextBgColor(int mTextBgColor) { this.mTextBgColor = mTextBgColor; } public int getmAlpha() { return mAlpha; } public void setmAlpha(int mAlpha) { this.mAlpha = mAlpha; }}
5. 开始使用自定义的View
1)在布局文件中引入View
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/colorAccent" > <cn.studyou.myviewdeep.view.WBottomTitleView android:layout_width="match_parent" android:layout_height="170dp" android:id="@+id/wCircleView" android:scaleType="fitXY" app:textDimension="18sp" app:textColor="#ffffff" /></RelativeLayout>
2) Activity中设置图片和标题
package cn.studyou.myviewdeep;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import com.bumptech.glide.Glide;import butterknife.BindView;import butterknife.ButterKnife;import cn.studyou.myviewdeep.view.WBottomTitleView;public class MainActivity extends AppCompatActivity { @BindView(R.id.wCircleView) WBottomTitleView wCircleView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); wCircleView.setTextString(" 今天天气不错,感觉挺好的。 "); Glide.with(this).load("http://img06.tooopen.com/images/20170214/tooopen_sy_198645593736.jpg").into(wCircleView); }}
6. 项目地址:https://github.com/wjie2014/MyViewDeep
简书地址:http://www.jianshu.com/p/cc0c1e9a836b
- Android 深入(一)- 自定义View之BottomTitleImageView
- android自定义view之地图(一)
- Android进阶之自定义view(一)
- 【Android进阶之自定义View(一)】
- android 自定义view之概述(一)
- android自定义View探索3(onMeasure深入分析一)
- android 自定义view之(一) Creating a View Class
- Android开发之自定义View专题(一):自定义柱形图
- Android自定义控件之自定义View(一)
- 自定义View深入了解(一)
- Android 自定义View(一)
- android-自定义View(一)
- android 自定义view(一)
- Android:自定义View(一)
- Android自定义View(一)
- android 自定义view(一)
- android自定义view(一)
- Android自定义View(一)
- java基础知识(十九)线程
- 数据库优化
- java状态模式
- Android Studio 打jar包
- c# System.Managemet的查询示例
- Android 深入(一)- 自定义View之BottomTitleImageView
- 如何利用yum的缓存文件
- cocos2d-x3.X 在Windows下打包Android平台APK
- mAP的一点理解
- OVM 免费虚拟化软件迭代时间调整,提高产品稳定性!
- Android Get,Post,AsyncHttpClient向服务器提交数据几种方式
- redis入门——redis常用命令
- 超详细:JAVA常用的设计模式汇总
- vs中检测内存泄漏的方法