自定义View(1)简单流程及示例模板
1,继承View , ViewGroup,或TextView等等
2,绘制相关的api,
- canvas 画布,
- paint 画笔
2,重写重要的函数(注意这个顺序)
- onMeasure 属于View的方法,用来测量自己及其中绘制内容的定宽度和高度
- onLayout 布局其内部view的位置和大小
- onSizeChanged 本view大小变化时的回调
- onDraw 在其中用绘制api 绘制本view
- onTouchEvent 处理感兴趣的事件,这里是touch事件
- view 还可以定义一些xml属性(少用)
示例代码
1 import android.app.Dialog; 2 import android.content.Context; 3 import android.graphics.Bitmap; 4 import android.graphics.BitmapFactory; 5 import android.graphics.Canvas; 6 import android.graphics.Color; 7 import android.graphics.DashPathEffect; 8 import android.graphics.LinearGradient; 9 import android.graphics.Paint; 10 import android.graphics.Paint.Align; 11 import android.graphics.Paint.FontMetrics; 12 import android.graphics.Path; 13 import android.graphics.PathEffect; 14 import android.graphics.PorterDuff.Mode; 15 import android.graphics.PorterDuffXfermode; 16 import android.graphics.Rect; 17 import android.graphics.RectF; 18 import android.graphics.Shader; 19 import android.graphics.Xfermode; 20 import android.util.AttributeSet; 21 import android.view.Gravity; 22 import android.view.MotionEvent; 23 import android.view.View; 24 import android.view.ViewGroup; 25 import android.widget.ListView; 26 import android.widget.SectionIndexer; 27 import android.widget.TextView; 28 29 import com.example.fastscroll.R; 30 31 public class CustomAlphabetFastScrollView extends View { 32 33 //下面3个是用于绘制,其中canvas,bitmap用于缓冲 34 Paint paint; 35 Canvas canvasForCache; 36 Bitmap bitmapForCache; 37 38 String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 39 SectionIndexer sectionIndexer; 40 ListView mListView; 41 int currentSection; 42 int baseline; 43 int bgColor; 44 int alphabetTxtColor; 45 int alphabetHighlightTxtColor; 46 47 Dialog sectionDlg; //显示section文本 48 TextView sectionText; //sectionDlg使用的view 49 50 /*属于View的方法,用来测量自己及其中绘制内容的定宽度和高度*/ 51 @Override 52 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 53 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 54 int width = MeasureSpec.getSize(widthMeasureSpec); 55 int height = MeasureSpec.getSize(heightMeasureSpec); 56 ViewGroup.LayoutParams l = getLayoutParams(); 57 if (l.width == ViewGroup.LayoutParams.WRAP_CONTENT) { 58 width = (int) paint.getTextSize()*2; 59 } 60 if (l.height == ViewGroup.LayoutParams.WRAP_CONTENT) { 61 height = (int) paint.getTextSize() * alphabet.length(); 62 } 63 setMeasuredDimension(width, height); 64 System.out.println(String.format("width = %d ,height = %d ", width,height)); 65 } 66 /*本view大小变化时的回调*/ 67 @Override 68 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 69 super.onSizeChanged(w, h, oldw, oldh); 70 bitmapForCache = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); 71 canvasForCache.setBitmap(bitmapForCache); 72 drawToCache(); 73 } 74 /*布局 子view在位置和大小*/ 75 @Override 76 protected void onLayout(boolean changed, int left, int top, int right, 77 int bottom) { 78 super.onLayout(changed, left, top, right, bottom); 79 } 80 @Override 81 public boolean onTouchEvent(MotionEvent event) { 82 switch (event.getAction()) { 83 case MotionEvent.ACTION_DOWN: 84 case MotionEvent.ACTION_MOVE: 85 setBackgroundColor(Color.parseColor("#8B7355")); 86 float y = event.getY() ; 87 for (int i = alphabet.length() - 1; i >= 0 ; --i) { 88 if ( i * paint.getTextSize() < y){ 89 currentSection = i; 90 sectionText.setText(alphabet.charAt(i) + ""); 91 if (mListView != null && sectionIndexer != null) { 92 int pos = sectionIndexer.getPositionForSection(currentSection); 93 mListView.setSelection(pos); 94 } 95 break; 96 } 97 } 98 sectionDlg.show(); 99 drawToCache(); 100 break; 101 case MotionEvent.ACTION_UP: 102 sectionDlg.dismiss(); 103 setBackgroundColor(bgColor); 104 break; 105 default: 106 break; 107 } 108 return true; 109 } 110 void clearCanvas(Canvas canvas){ 111 Xfermode old = paint.getXfermode(); 112 paint.setXfermode(new PorterDuffXfermode(Mode.CLEAR)); 113 canvasForCache.drawPaint(paint); 114 paint.setXfermode(old); 115 } 116 void drawToCache(){ 117 clearCanvas(canvasForCache); 118 canvasForCache.save(); 119 paint.setColor(bgColor); 120 Rect outRect = new Rect(); 121 getDrawingRect(outRect); 122 canvasForCache.drawRect(outRect, paint); 123 int viewHeight = getHeight(); 124 int sectionHeight = viewHeight / alphabet.length(); 125 int diff = viewHeight - sectionHeight * alphabet.length(); 126 baseline = sectionHeight + diff/2; 127 paint.setColor(alphabetTxtColor); 128 canvasForCache.drawLine(0, baseline, getWidth(), baseline, paint); 129 paint.setTextSize(sectionHeight); 130 for (int i = 0; i < alphabet.length(); ++i){ 131 if (currentSection == i){ 132 paint.setColor(alphabetHighlightTxtColor); 133 }else{ 134 paint.setColor(alphabetTxtColor); 135 } 136 canvasForCache.drawText("" + alphabet.charAt(i), 0, baseline + sectionHeight * i, paint); 137 } 138 canvasForCache.restore(); 139 } 140 141 void init(){ 142 bgColor = Color.parseColor("#00E3E3E3"); 143 alphabetTxtColor = Color.BLACK; 144 alphabetHighlightTxtColor = Color.parseColor("#FF00FF"); 145 146 paint = new Paint(Paint.ANTI_ALIAS_FLAG); 147 paint.setStyle(Paint.Style.FILL); 148 paint.setColor(bgColor); 149 paint.setTextAlign(Paint.Align.LEFT); 150 151 canvasForCache = new Canvas(); 152 sectionText = new TextView(getContext()); 153 sectionText.setMinEms(2); 154 sectionText.setGravity(Gravity.CENTER); 155 sectionText.setWidth((int) (paint.getTextSize()*4)); 156 sectionText.setHeight((int) (paint.getTextSize()*4)); 157 sectionDlg = new Dialog(getContext(),R.style.customDlgTheme); 158 sectionDlg.setContentView(sectionText); 159 } 160 161 void drawSample(Canvas canvas) { 162 /* 163 * 方法 说明 drawRect 绘制矩形 drawCircle 绘制圆形 drawOval 绘制椭圆 drawPath 绘制路径 164 * drawLine 绘制直线 drawPoin 绘制点 165 */ 166 // 创建画笔 167 Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); 168 int txtSize = 24; 169 paint.setTextSize(txtSize); 170 /*画点*/ 171 paint.setStyle(Paint.Style.FILL); 172 canvas.drawText("画点:", 10, txtSize, paint); 173 paint.setColor(Color.RED); 174 float stroke = paint.getStrokeWidth(); 175 paint.setStrokeWidth(3); 176 canvas.drawPoint(100, 20, paint);// 画一个点 177 canvas.drawPoints(new float[] { 170, 20, 180, 20, 190, 20 }, paint);// 画多个点 178 paint.setStrokeWidth(stroke); 179 180 181 /*画线*/ 182 paint.setColor(Color.BLACK); 183 canvas.drawText("画线:", 10, 54, paint); 184 canvas.drawLine(110, 40, 200, 40, paint);// 画线 185 canvas.drawLine(210, 40, 400, 55, paint);// 斜线 186 187 /*画虚线*/ 188 canvas.drawText("画虚线:", 10,84, paint); 189 paint.setStyle(Paint.Style.STROKE); 190 Path path3 = new Path(); 191 path3.moveTo(110, 84); 192 path3.lineTo(400,84); 193 /*DashPathEffect第一个参数必须为偶数个整数,其中偶数位上的整数表示绘制的间隔,奇数位上的整数表示不绘制的间隔。*/ 194 PathEffect effects = new DashPathEffect(new float[]{5,30,5,30,5,30},1); 195 PathEffect oldEffect = paint.getPathEffect(); 196 paint.setPathEffect(effects); 197 canvas.drawPath(path3, paint); 198 199 /*画弧线*/ 200 paint.setPathEffect(oldEffect); 201 canvas.drawText("画弧线:", 10, 124, paint); 202 203 RectF oval1 = new RectF(170, 114, 190, 134); // 弧线是画在矩形中的 204 canvas.drawArc(oval1, 180, 180, false, paint); // 左眼弧线 ^_^ 205 206 oval1.set(230, 114, 250, 134); 207 canvas.drawArc(oval1, 180, 180, false, paint); // 右眼弧线 ^_^ 208 209 oval1.set(190, 124, 230, 134); 210 canvas.drawArc(oval1, 0, 180, false, paint); // 嘴弧线 ^_^ 211 212 /*画贝塞尔曲线*/ 213 /* Path类封装复合(多轮廓几何图形的路径 214 * 由直线段*、二次曲线,和三次方曲线,也可画以油画。drawPath(路径、油漆),要么已填充的或抚摸 215 * (基于油漆的风格),或者可以用于剪断或画画的文本在路径。 216 */ 217 canvas.drawText("画贝塞尔曲线:", 10, 174, paint); 218 Path path2 = new Path(); 219 path2.moveTo(170, 174); // 设置Path的起点 220 path2.quadTo(400, 120, 450, 600); // 设置贝塞尔曲线的控制点坐标和终点坐标 221 canvas.drawPath(path2, paint); // 画出贝塞尔曲线 222 223 /*画圆*/ 224 canvas.drawText("画圆:", 10, 214, paint); // 画文本 225 canvas.drawCircle(150, 204, 10, paint); // 小圆 226 paint.setAntiAlias(true); // 设置画笔的锯齿效果。true是去除 227 canvas.drawCircle(200, 204, 20, paint); // 大圆 228 229 /*画扇形和椭圆*/ 230 canvas.drawText("画扇形和椭圆:", 10, 274, paint); 231 /*设置渐变色 这个正方形的颜色是改变的 */ 232 Shader mShader = new LinearGradient(0, 0, 200, 244, 233 new int[] { Color.RED, Color.GREEN, Color.BLUE, Color.YELLOW, 234 Color.LTGRAY }, null, Shader.TileMode.REPEAT); // 一个材质,打造出一个线性梯度沿著一条线。 235 paint.setShader(mShader); 236 // p.setColor(Color.BLUE); 237 238 // 画扇形,drawArc第一个参数是RectF:该类是第二个参数是角度的开始,第三个参数是多少度,第四个参数是真的时候画扇形,是假的时候画弧线 239 RectF oval2 = new RectF(170, 244, 250, 320);// 设置个新的长方形,扫描测量 240 canvas.drawArc(oval2, 200, 130, true, paint); 241 242 // 画椭圆,把oval改一下 243 oval2.set(250, 244,320,274); 244 canvas.drawOval(oval2, paint); 245 246 /*画矩形*/ 247 canvas.drawText("画矩形:", 10, 320, paint); 248 paint.setStyle(Paint.Style.FILL);// 设置填满 249 canvas.drawRect(150, 300, 170, 320, paint);// 正方形 250 canvas.drawRect(180, 300, 250, 320, paint);// 长方形 251 252 /*画圆角矩形*/ 253 canvas.drawText("画圆角矩形:", 10, 360, paint); 254 paint.setStyle(Paint.Style.FILL);// 充满 255 paint.setColor(Color.LTGRAY); 256 paint.setAntiAlias(true);// 设置画笔的锯齿效果 257 RectF oval3 = new RectF(160, 330, 300, 360);// 设置个新的长方形 258 canvas.drawRoundRect(oval3, 20, 15, paint);// 第二个参数是x半径,第三个参数是y半径 259 260 /*画三角形*/ 261 canvas.drawText("画三角形:", 10, 400, paint); 262 // 绘制这个三角形,你可以绘制任意多边形 263 Path path = new Path(); 264 path.moveTo(160, 380);// 此点为多边形的起点 265 path.lineTo(300, 380); 266 path.lineTo(200, 430); 267 // path.lineTo(160, 380); 268 path.close(); // 使这些点构成封闭的多边形,就不用画回到起点 path.lineTo(160, 380); 269 canvas.drawPath(path, paint); 270 271 /*画任意多边形,*/ 272 paint.setShader(null); 273 canvas.drawText("画任意多边形:", 10, 460, paint); 274 paint.setColor(Color.LTGRAY); 275 paint.setStyle(Paint.Style.STROKE);// 设置空心 276 Path path1 = new Path(); 277 path1.moveTo(180, 450); 278 path1.lineTo(300, 450); 279 path1.lineTo(310, 460); 280 path1.lineTo(180, 470); 281 path1.close(); // 封闭形状 282 canvas.drawPath(path1, paint); 283 284 /*画图片,就是贴图*/ 285 canvas.drawText("画图片:", 10, 520, paint); 286 Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher); 287 canvas.drawBitmap(bitmap, 150, 460, paint); 288 289 /*画文本*/ 290 paint.setColor(Color.BLACK); 291 canvas.drawText("画文本:", 10, 670, paint); 292 paint.setTextSize(txtSize * 3); 293 paint.setStyle(Paint.Style.FILL); 294 295 FontMetrics fontMetrics = paint.getFontMetrics(); 296 float originX = 200; 297 float originY = 700; 298 float topY = originY + fontMetrics.top; 299 float ascentY = originY + fontMetrics.ascent; 300 float descentY = originY + fontMetrics.descent; 301 float bottomY = originY + fontMetrics.bottom; 302 float leading = fontMetrics.leading; 303 304 //文本 305 paint.setColor(Color.RED); 306 paint.setTextAlign(Align.LEFT); 307 canvas.drawText("text1", originX , originY, paint); 308 309 //origin point 310 canvas.drawCircle(originX, originY, 5, paint); 311 paint.setTextAlign(Align.LEFT); 312 313 //baseline 314 paint.setColor(Color.LTGRAY); 315 paint.setTextSize(txtSize); 316 canvas.drawText("baseline", originX - 100 , originY, paint); 317 canvas.drawLine(originX, originY, originX + 140, originY, paint); 318 319 //top line 320 paint.setColor(Color.GREEN); 321 canvas.drawText("topline", originX - 80, topY, paint); 322 canvas.drawLine(originX, topY, originX + 100, topY, paint); 323 324 //ascent line 325 paint.setColor(Color.CYAN); 326 canvas.drawText("ascent line", originX + 155, ascentY, paint); 327 canvas.drawLine(originX+50, ascentY, originX + 150, ascentY, paint); 328 329 //descent line 330 paint.setColor(Color.YELLOW); 331 canvas.drawText("descent line", originX + 140, descentY, paint); 332 canvas.drawLine(originX+30, descentY, originX + 139, descentY, paint); 333 334 //bottom line 335 paint.setColor(Color.BLUE); 336 canvas.drawText("bottom line", originX - 155, descentY, paint); 337 canvas.drawLine(originX-30, bottomY, originX + 110, bottomY, paint); 338 } 339 340 @Override 341 protected void onDraw(Canvas canvas) { 342 drawSample(canvas); 343 // canvas.drawBitmap(bitmapForCache, 0,0, paint); 344 // 345 // canvas.save(); 346 // 347 // int viewHeight = getHeight(); 348 // int sectionHeight = viewHeight / alphabet.length(); 349 // int diff = viewHeight - sectionHeight * alphabet.length(); 350 // 351 // paint.setStrokeWidth(3); 352 // paint.setColor(Color.RED); 353 // canvas.drawPoint(0,0, paint); 354 // 355 // paint.setColor(alphabetTxtColor); 356 // baseline = sectionHeight + diff/2; 357 //// canvas.drawLine(0, baseline, getWidth(), baseline, paint); 358 // paint.setTextSize(sectionHeight); 359 // 360 // 361 // for (int i = 0; i < alphabet.length(); ++i){ 362 // if (currentSection == i){ 363 // paint.setColor(alphabetHighlightTxtColor); 364 // }else{ 365 // paint.setColor(alphabetTxtColor); 366 // } 367 // canvas.drawText("" + alphabet.charAt(i), getWidth()/2, baseline + sectionHeight * i, paint); 368 // } 369 // canvas.restore(); 370 } 371 public CustomAlphabetFastScrollView(Context context, AttributeSet attrs) { 372 super(context, attrs); 373 init(); 374 } 375 }