1,继承View , ViewGroup,或TextView等等

2,绘制相关的api,

  • canvas 画布,
  • paint 画笔

2,重写重要的函数(注意这个顺序)

  • onMeasure 属于View的方法,用来测量自己及其中绘制内容的定宽度和高度
  • onLayout  布局其内部view的位置和大小
  • onSizeChanged 本view大小变化时的回调
  • onDraw  在其中用绘制api 绘制本view
  • onTouchEvent  处理感兴趣的事件,这里是touch事件
  • view 还可以定义一些xml属性(少用)

示例代码

 import android.app.Dialog;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Paint.FontMetrics;
import android.graphics.Path;
import android.graphics.PathEffect;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.Xfermode;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import android.widget.SectionIndexer;
import android.widget.TextView; import com.example.fastscroll.R; public class CustomAlphabetFastScrollView extends View { //下面3个是用于绘制,其中canvas,bitmap用于缓冲
Paint paint;
Canvas canvasForCache;
Bitmap bitmapForCache; String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
SectionIndexer sectionIndexer;
ListView mListView;
int currentSection;
int baseline;
int bgColor;
int alphabetTxtColor;
int alphabetHighlightTxtColor; Dialog sectionDlg; //显示section文本
TextView sectionText; //sectionDlg使用的view /*属于View的方法,用来测量自己及其中绘制内容的定宽度和高度*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
ViewGroup.LayoutParams l = getLayoutParams();
if (l.width == ViewGroup.LayoutParams.WRAP_CONTENT) {
width = (int) paint.getTextSize()*;
}
if (l.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
height = (int) paint.getTextSize() * alphabet.length();
}
setMeasuredDimension(width, height);
System.out.println(String.format("width = %d ,height = %d ", width,height));
}
/*本view大小变化时的回调*/
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
bitmapForCache = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
canvasForCache.setBitmap(bitmapForCache);
drawToCache();
}
/*布局 子view在位置和大小*/
@Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
super.onLayout(changed, left, top, right, bottom);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
setBackgroundColor(Color.parseColor("#8B7355"));
float y = event.getY() ;
for (int i = alphabet.length() - ; i >= ; --i) {
if ( i * paint.getTextSize() < y){
currentSection = i;
sectionText.setText(alphabet.charAt(i) + "");
if (mListView != null && sectionIndexer != null) {
int pos = sectionIndexer.getPositionForSection(currentSection);
mListView.setSelection(pos);
}
break;
}
}
sectionDlg.show();
drawToCache();
break;
case MotionEvent.ACTION_UP:
sectionDlg.dismiss();
setBackgroundColor(bgColor);
break;
default:
break;
}
return true;
}
void clearCanvas(Canvas canvas){
Xfermode old = paint.getXfermode();
paint.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
canvasForCache.drawPaint(paint);
paint.setXfermode(old);
}
void drawToCache(){
clearCanvas(canvasForCache);
canvasForCache.save();
paint.setColor(bgColor);
Rect outRect = new Rect();
getDrawingRect(outRect);
canvasForCache.drawRect(outRect, paint);
int viewHeight = getHeight();
int sectionHeight = viewHeight / alphabet.length();
int diff = viewHeight - sectionHeight * alphabet.length();
baseline = sectionHeight + diff/;
paint.setColor(alphabetTxtColor);
canvasForCache.drawLine(, baseline, getWidth(), baseline, paint);
paint.setTextSize(sectionHeight);
for (int i = ; i < alphabet.length(); ++i){
if (currentSection == i){
paint.setColor(alphabetHighlightTxtColor);
}else{
paint.setColor(alphabetTxtColor);
}
canvasForCache.drawText("" + alphabet.charAt(i), , baseline + sectionHeight * i, paint);
}
canvasForCache.restore();
} void init(){
bgColor = Color.parseColor("#00E3E3E3");
alphabetTxtColor = Color.BLACK;
alphabetHighlightTxtColor = Color.parseColor("#FF00FF"); paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.FILL);
paint.setColor(bgColor);
paint.setTextAlign(Paint.Align.LEFT); canvasForCache = new Canvas();
sectionText = new TextView(getContext());
sectionText.setMinEms();
sectionText.setGravity(Gravity.CENTER);
sectionText.setWidth((int) (paint.getTextSize()*));
sectionText.setHeight((int) (paint.getTextSize()*));
sectionDlg = new Dialog(getContext(),R.style.customDlgTheme);
sectionDlg.setContentView(sectionText);
} void drawSample(Canvas canvas) {
/*
* 方法 说明 drawRect 绘制矩形 drawCircle 绘制圆形 drawOval 绘制椭圆 drawPath 绘制路径
* drawLine 绘制直线 drawPoin 绘制点
*/
// 创建画笔
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
int txtSize = ;
paint.setTextSize(txtSize);
/*画点*/
paint.setStyle(Paint.Style.FILL);
canvas.drawText("画点:", , txtSize, paint);
paint.setColor(Color.RED);
float stroke = paint.getStrokeWidth();
paint.setStrokeWidth();
canvas.drawPoint(, , paint);// 画一个点
canvas.drawPoints(new float[] { , , , , , }, paint);// 画多个点
paint.setStrokeWidth(stroke); /*画线*/
paint.setColor(Color.BLACK);
canvas.drawText("画线:", , , paint);
canvas.drawLine(, , , , paint);// 画线
canvas.drawLine(, , , , paint);// 斜线 /*画虚线*/
canvas.drawText("画虚线:", ,, paint);
paint.setStyle(Paint.Style.STROKE);
Path path3 = new Path();
path3.moveTo(, );
path3.lineTo(,);
/*DashPathEffect第一个参数必须为偶数个整数,其中偶数位上的整数表示绘制的间隔,奇数位上的整数表示不绘制的间隔。*/
PathEffect effects = new DashPathEffect(new float[]{,,,,,},);
PathEffect oldEffect = paint.getPathEffect();
paint.setPathEffect(effects);
canvas.drawPath(path3, paint); /*画弧线*/
paint.setPathEffect(oldEffect);
canvas.drawText("画弧线:", , , paint); RectF oval1 = new RectF(, , , ); // 弧线是画在矩形中的
canvas.drawArc(oval1, , , false, paint); // 左眼弧线 ^_^ oval1.set(, , , );
canvas.drawArc(oval1, , , false, paint); // 右眼弧线 ^_^ oval1.set(, , , );
canvas.drawArc(oval1, , , false, paint); // 嘴弧线 ^_^ /*画贝塞尔曲线*/
/* Path类封装复合(多轮廓几何图形的路径
* 由直线段*、二次曲线,和三次方曲线,也可画以油画。drawPath(路径、油漆),要么已填充的或抚摸
* (基于油漆的风格),或者可以用于剪断或画画的文本在路径。
*/
canvas.drawText("画贝塞尔曲线:", , , paint);
Path path2 = new Path();
path2.moveTo(, ); // 设置Path的起点
path2.quadTo(, , , ); // 设置贝塞尔曲线的控制点坐标和终点坐标
canvas.drawPath(path2, paint); // 画出贝塞尔曲线 /*画圆*/
canvas.drawText("画圆:", , , paint); // 画文本
canvas.drawCircle(, , , paint); // 小圆
paint.setAntiAlias(true); // 设置画笔的锯齿效果。true是去除
canvas.drawCircle(, , , paint); // 大圆 /*画扇形和椭圆*/
canvas.drawText("画扇形和椭圆:", , , paint);
/*设置渐变色 这个正方形的颜色是改变的 */
Shader mShader = new LinearGradient(, , , ,
new int[] { Color.RED, Color.GREEN, Color.BLUE, Color.YELLOW,
Color.LTGRAY }, null, Shader.TileMode.REPEAT); // 一个材质,打造出一个线性梯度沿著一条线。
paint.setShader(mShader);
// p.setColor(Color.BLUE); // 画扇形,drawArc第一个参数是RectF:该类是第二个参数是角度的开始,第三个参数是多少度,第四个参数是真的时候画扇形,是假的时候画弧线
RectF oval2 = new RectF(, , , );// 设置个新的长方形,扫描测量
canvas.drawArc(oval2, , , true, paint); // 画椭圆,把oval改一下
oval2.set(, ,,);
canvas.drawOval(oval2, paint); /*画矩形*/
canvas.drawText("画矩形:", , , paint);
paint.setStyle(Paint.Style.FILL);// 设置填满
canvas.drawRect(, , , , paint);// 正方形
canvas.drawRect(, , , , paint);// 长方形 /*画圆角矩形*/
canvas.drawText("画圆角矩形:", , , paint);
paint.setStyle(Paint.Style.FILL);// 充满
paint.setColor(Color.LTGRAY);
paint.setAntiAlias(true);// 设置画笔的锯齿效果
RectF oval3 = new RectF(, , , );// 设置个新的长方形
canvas.drawRoundRect(oval3, , , paint);// 第二个参数是x半径,第三个参数是y半径 /*画三角形*/
canvas.drawText("画三角形:", , , paint);
// 绘制这个三角形,你可以绘制任意多边形
Path path = new Path();
path.moveTo(, );// 此点为多边形的起点
path.lineTo(, );
path.lineTo(, );
// path.lineTo(160, 380);
path.close(); // 使这些点构成封闭的多边形,就不用画回到起点 path.lineTo(160, 380);
canvas.drawPath(path, paint); /*画任意多边形,*/
paint.setShader(null);
canvas.drawText("画任意多边形:", , , paint);
paint.setColor(Color.LTGRAY);
paint.setStyle(Paint.Style.STROKE);// 设置空心
Path path1 = new Path();
path1.moveTo(, );
path1.lineTo(, );
path1.lineTo(, );
path1.lineTo(, );
path1.close(); // 封闭形状
canvas.drawPath(path1, paint); /*画图片,就是贴图*/
canvas.drawText("画图片:", , , paint);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher);
canvas.drawBitmap(bitmap, , , paint); /*画文本*/
paint.setColor(Color.BLACK);
canvas.drawText("画文本:", , , paint);
paint.setTextSize(txtSize * );
paint.setStyle(Paint.Style.FILL); FontMetrics fontMetrics = paint.getFontMetrics();
float originX = ;
float originY = ;
float topY = originY + fontMetrics.top;
float ascentY = originY + fontMetrics.ascent;
float descentY = originY + fontMetrics.descent;
float bottomY = originY + fontMetrics.bottom;
float leading = fontMetrics.leading; //文本
paint.setColor(Color.RED);
paint.setTextAlign(Align.LEFT);
canvas.drawText("text1", originX , originY, paint); //origin point
canvas.drawCircle(originX, originY, , paint);
paint.setTextAlign(Align.LEFT); //baseline
paint.setColor(Color.LTGRAY);
paint.setTextSize(txtSize);
canvas.drawText("baseline", originX - , originY, paint);
canvas.drawLine(originX, originY, originX + , originY, paint); //top line
paint.setColor(Color.GREEN);
canvas.drawText("topline", originX - , topY, paint);
canvas.drawLine(originX, topY, originX + , topY, paint); //ascent line
paint.setColor(Color.CYAN);
canvas.drawText("ascent line", originX + , ascentY, paint);
canvas.drawLine(originX+, ascentY, originX + , ascentY, paint); //descent line
paint.setColor(Color.YELLOW);
canvas.drawText("descent line", originX + , descentY, paint);
canvas.drawLine(originX+, descentY, originX + , descentY, paint); //bottom line
paint.setColor(Color.BLUE);
canvas.drawText("bottom line", originX - , descentY, paint);
canvas.drawLine(originX-, bottomY, originX + , bottomY, paint);
} @Override
protected void onDraw(Canvas canvas) {
drawSample(canvas);
// canvas.drawBitmap(bitmapForCache, 0,0, paint);
//
// canvas.save();
//
// int viewHeight = getHeight();
// int sectionHeight = viewHeight / alphabet.length();
// int diff = viewHeight - sectionHeight * alphabet.length();
//
// paint.setStrokeWidth(3);
// paint.setColor(Color.RED);
// canvas.drawPoint(0,0, paint);
//
// paint.setColor(alphabetTxtColor);
// baseline = sectionHeight + diff/2;
//// canvas.drawLine(0, baseline, getWidth(), baseline, paint);
// paint.setTextSize(sectionHeight);
//
//
// for (int i = 0; i < alphabet.length(); ++i){
// if (currentSection == i){
// paint.setColor(alphabetHighlightTxtColor);
// }else{
// paint.setColor(alphabetTxtColor);
// }
// canvas.drawText("" + alphabet.charAt(i), getWidth()/2, baseline + sectionHeight * i, paint);
// }
// canvas.restore();
}
public CustomAlphabetFastScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
}

自定义View(1)简单流程及示例模板的更多相关文章

  1. 自定义View分类与流程

    自定义View分类与流程(进阶篇)## 转载出处: http://www.gcssloop.com/customview/CustomViewProcess/ 自定义View绘制流程函数调用链(简化版 ...

  2. Android查缺补漏(View篇)--自定义 View 的基本流程

    View是Android很重要的一部分,常用的View有Button.TextView.EditView.ListView.GridView.各种layout等等,开发者通过对这些View的各种组合以 ...

  3. 自定义View的基本流程

    1.明确需求,确定你想实现的效果2.确定是使用组合控件的形式还是全新自定义的形式,组合控件即使用多个系统控件来合成一个新控件,你比如titilebar,这种形式相对简单,参考:http://blog. ...

  4. 从一个简洁的进度刻度绘制中了解自定义View的思路流程

    先看效果(原谅我的渣像素),进度的刻度.宽度.颜色可以随意设定: [项目github地址: https://github.com/zhangke3016/CircleLoading] 实现起来并不难, ...

  5. 自定义View的实现流程

    1.继承View组件,比如,LabelView继承了View   2.重写两个构造方法,比如,对于自定义View LabelView   LabelView(Context context),如果该自 ...

  6. 自定义View绘制简单的圆环的实现

    package com.loaderman.mywave; import android.content.Context; import android.graphics.Canvas; import ...

  7. 自定义控件(视图)2期笔记01:自定义控件之自定义View的步骤

    1. 根据Android Developers官网的介绍,自定义控件你需要以下的步骤: (1)创建View (2)处理View的布局 (3)绘制View (4)与用户进行交互 (5)优化已定义的Vie ...

  8. Android查缺补漏(View篇)--自定义View利器Canvas和Paint详解

    上篇文章介绍了自定义View的创建流程,从宏观上给出了一个自定义View的创建步骤,本篇是上一篇文章的延续,介绍了自定义View中两个必不可少的工具Canvas和Paint,从细节上更进一步的讲解自定 ...

  9. 自定义View实战--实现一个清新美观的加载按钮

    本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 在 Dribble 上偶然看到了一组交互如下: 当时在心里问自己能不能做,答案肯定是能做的,不过我比较懒,觉得中间那个伸缩变化要编写 ...

随机推荐

  1. andriod ADB命令的使用

    android ADB命令的使用 ADB是一个 客户端-服务器端 程序, 其中客户端是你用来操作的电脑, 服务器端是android设备. 先说安装方法, 电脑上需要安装客户端. 客户端包含在sdk里. ...

  2. 从零开始学ios开发(五):IOS控件(2),Slider

    下面继续学习ios的其他控件,这次会使用到的控件有Slider,当然还有一些之前已经使用过的控件Label. 这次我们不新建一个project了,当然如果你愿意重新创建一个新的项目也完全可以,我们还是 ...

  3. 分布式文件系统 - FastDFS

    分布式文件系统 - FastDFS 别问我在哪里 也许我早已不是我自己,别问我在哪里,我一直在这里. 突然不知道说些什么了... 初识 FastDFS 记得那是我刚毕业后进入的第一家公司,一个技术小白 ...

  4. cocos中BatchNode精灵集合的使用

    1.CCSpriteBatchNode是为了提高渲染效率而实现的,它继承自CCNode 2.fps:帧率,是游戏中衡量流畅度的一个很重要的概念,cocos中默认的帧率是60,即一秒刷新60帧 3.精灵 ...

  5. ASP.NET Web - 服务器控件

    控件 HTML 说明 Label <span> 返回一个包含文本的span元素 Literal static text 返回简单的静态文本.使用Literal控件,可以根据客户应用程序转换 ...

  6. WPF 多线程处理(4)

    WPF 多线程处理(1) WPF 多线程处理(2) WPF 多线程处理(3) WPF 多线程处理(4) WPF 多线程处理(5) WPF 多线程处理(6) 开始一个线程处理读取的文件并且更新到list ...

  7. ListView防止滑动变色的小技巧

    listview滑动时会变成白色,如果背景色不是白色的话可以通过设置setCacheColorHint(Color.TRANSPARENT);来避免变色,.对应的xml也可以进行设置.

  8. Discuz!NT 后台任意文件上传的源代码修补方法

    相关的漏洞介绍: http://www.wooyun.org/bugs/wooyun-2013-035199 Discuz!NT 管理后台可以自定义文件类型,从而造成任意文件上传,测试过程中 aspx ...

  9. 1067: [SCOI2007]降雨量 - BZOJ

    Description 我们常常会说这样的话:“X年是自Y年以来降雨量最多的”.它的含义是X年的降雨量不超过Y年,且对于任意Y<Z<X,Z年的降雨量严格小于X年.例如2002,2003,2 ...

  10. git如何ignore

    今天新建了一个项目传到git上,但是每次编译都会有一些无用的文件生成,于是就编写了ignore.但是发现无用.因为你的文件已经上传到服务器了,再编写ignore就无用了,ignore的适用是文件没上传 ...