51、自定义View基础和原理
2015-11-04 09:59
453 查看
一、编写自己的自定义View
最简单的自定义View,继承View
通过覆盖View的onDraw方法来实现自主显示
利用Canvas和paint来绘制显示元素(文字,几何图形等)
二、加入逻辑线程
让文字动起来,改变坐标
在线程中修改坐标(加入循环,时间睡眠)
重新绘制元素(两种方式)
线程休眠时间控制(去除逻辑处理时间)
把以上代码进行封装。
三、利用xml中定义样式来影响显示效果
在xml中定义样式和属性
在布局中使用属性(命名空间需要声明)
在代码中解析样式的属性
在代码中使用属性对显示效果产生影响
范例:绘制相同的文字,不同的行数。从左边移动到右边。
布局文件:activity_main.xml
四、通过代码添加自定义控件。
setContentView(new MyView(this));
最简单的自定义View,继承View
通过覆盖View的onDraw方法来实现自主显示
利用Canvas和paint来绘制显示元素(文字,几何图形等)
<com.myview.v1.MyView android:layout_width="match_parent" android:layout_height="match_parent" android:background="#00ff00" />
public class MyView extends View { private Bitmap bitmap; public MyView(Context context, AttributeSet attrs) { super(context, attrs); bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher); } public MyView(Context context) { super(context); bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher); } @Override // 加入绘制元素 protected void onDraw(Canvas canvas) { Paint paint = new Paint(); paint.setTextSize(30); // a,r,g,b(透明度,红色,绿色,蓝色) paint.setColor(0xffff0000); /** * 绘制文字 * Android 中绘制文字的方向是,左下。 所以需要把Y坐标改成30下移,就可以显示了。 * 0, 30 分别为 X Y坐标 * drawText(String text, float x, float y, Paint paint) */ canvas.drawText("this is onDraw", 0, 30, paint); /** * drawLine(float startX, float startY, float stopX, float stopY, Paint paint) * 在文字下30的地方绘制一条线,所以开始和结束的Y坐标就是(30+30)。 */ canvas.drawLine(0, 60, 100, 60, paint); paint.setStyle(Style.STROKE); // 通过坐标绘制矩形 // canvas.drawRect(0, 90, 100, 190, paint); // 通过Rect绘制矩形 // Rect r = new Rect(0, 90, 100, 190); // canvas.drawRect(r, paint); // 通过RectF绘制矩形 RectF rect = new RectF(0, 90, 100, 190); // canvas.drawRect(rect, paint); // 绘制圆角矩形 // drawRoundRect(RectF rect, float rx, float ry, Paint paint) canvas.drawRoundRect(rect, 10, 10, paint); // 绘制圆形 canvas.drawCircle(50, 270, 50, paint); canvas.drawBitmap(bitmap, 0, 350, paint); } }
二、加入逻辑线程
让文字动起来,改变坐标
在线程中修改坐标(加入循环,时间睡眠)
重新绘制元素(两种方式)
线程休眠时间控制(去除逻辑处理时间)
import java.util.Random; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.RectF; import android.util.AttributeSet; import android.view.View; public class LogicView extends View { // 实例化 画笔。 private Paint paint = new Paint(); // private float rx = 0; // 添加线程属性 private MyThread thread; /** * 绘制在文字下,30的地方。 * RectF(float left, float top, float right, float bottom) * 0 30+30 宽度100 60+100 */ private RectF rectF = new RectF(0, 60, 100, 160); // 区间角度 private float sweepAngle = 0; // 在布局当中使用。 public LogicView(Context context, AttributeSet attrs) { super(context, attrs); } // 在代码当中使用。 public LogicView(Context context) { super(context); } @Override protected void onDraw(Canvas canvas) { paint.setTextSize(30); canvas.drawText("LogicView", rx, 30, paint); /** * 绘制一个圆。 * drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint) * sweepAngle:区间角度。 * useCenter:true ,false. 绘制的效果不同。 */ canvas.drawArc(rectF, 0, sweepAngle, true, paint); if (thread == null) { thread = new MyThread(); thread.start(); } } class MyThread extends Thread { // 随机对象,产生随机值。 Random rand = new Random(); @Override public void run() { while (true) { rx += 3; // 当超出屏幕的宽度时。 if (rx > getWidth()) { /** * 走出屏幕后,重新回到屏幕。 * 0 - 文字的宽度,这样 “LogicView”文字,从左边出来的时候, * 就可以从w开始一点点移出屏幕。 */ rx = 0 - paint.measureText("LogicView"); } sweepAngle++; if (sweepAngle > 360) { sweepAngle = 0; } // 取到 0-255的随机数。 int r = rand.nextInt(256); int g = rand.nextInt(256); int b = rand.nextInt(256); // 设置颜色。 paint.setARGB(255, r, g, b); postInvalidate(); // 重绘 try { Thread.sleep(30); // 睡眠30毫秒 } catch (InterruptedException e) { e.printStackTrace(); } } } } }
把以上代码进行封装。
import android.content.Context; import android.graphics.Canvas; import android.util.AttributeSet; import android.view.View; // 基类 public abstract class BaseView extends View { private MyThread thread; private boolean running = true; public BaseView(Context context, AttributeSet attrs) { super(context, attrs); } public BaseView(Context context) { super(context); } protected abstract void drawSub(Canvas canvas); protected abstract void logic(); @Override protected final void onDraw(Canvas canvas) { if (thread == null) { thread = new MyThread(); thread.start(); } else { drawSub(canvas); } } @Override protected void onDetachedFromWindow() { running = false; super.onDetachedFromWindow(); } class MyThread extends Thread { @Override public void run() { while (running) { logic(); postInvalidate(); try { Thread.sleep(30); } catch (InterruptedException e) { e.printStackTrace(); } } } } }
import java.util.Random; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.RectF; import android.util.AttributeSet; public class LogicView extends BaseView { private Paint paint = new Paint(); private float rx = 0; private RectF rectF = new RectF(0, 60, 100, 160); private float sweepAngle = 0; Random rand = new Random(); public LogicView(Context context, AttributeSet attrs) { super(context, attrs); } public LogicView(Context context) { super(context); } @Override protected void drawSub(Canvas canvas) { paint.setTextSize(30); canvas.drawText("LogicView", rx, 30, paint); canvas.drawArc(rectF, 0, sweepAngle, true, paint); } @Override protected void logic() { rx += 3; if (rx > getWidth()) { rx = 0 - paint.measureText("LogicView"); } sweepAngle++; if (sweepAngle > 360) { sweepAngle = 0; } int r = rand.nextInt(256); int g = rand.nextInt(256); int b = rand.nextInt(256); paint.setARGB(255, r, g, b); } }
import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.util.AttributeSet; public class MyText extends BaseView { private Paint paint = new Paint(); private float rx = 0; public MyText(Context context, AttributeSet attrs) { super(context, attrs); } public MyText(Context context) { super(context); } @Override protected void drawSub(Canvas canvas) { paint.setTextSize(30); canvas.drawText("MyText", rx, 30, paint); } @Override protected void logic() { rx += 3; if (rx > getWidth()) { rx = -paint.measureText("MyText"); } } }
三、利用xml中定义样式来影响显示效果
在xml中定义样式和属性
在布局中使用属性(命名空间需要声明)
在代码中解析样式的属性
在代码中使用属性对显示效果产生影响
范例:绘制相同的文字,不同的行数。从左边移动到右边。
布局文件:activity_main.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:nt="http://schemas.android.com/apk/res/com.myview" android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" > nt:这个名字是自定义的。 <com.myview.v4.NumText android:layout_width="match_parent" android:layout_height="match_parent" nt:lineNum="6" nt:xScroll="true"/> </FrameLayout>
import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; import android.util.AttributeSet; import com.myview.R; import com.myview.v3.BaseView; // 效果:竖着一排文字,无限 从左移动到右边 public class NumText extends BaseView { private Paint paint = new Paint(); private int lineNum = 0; private int mx = 0; private boolean xScroll = false; public NumText(Context context) { super(context); } public NumText(Context context, AttributeSet attrs) { super(context, attrs); // 在代码中解析 “样式属性”。 TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.NumText); // 1 是默认的一行。 lineNum = ta.getInt(R.styleable.NumText_lineNum, 1); // 默认为不滚动(文字从左滚动到右边) xScroll = ta.getBoolean(R.styleable.NumText_xScroll, false); ta.recycle(); } @Override protected void drawSub(Canvas canvas) { for (int i = 0; i < lineNum; i++) { int textSize = 30 + i; paint.setTextSize(textSize); canvas.drawText("百度百科", mx, textSize + textSize * i, paint); } } @Override protected void logic() { if (xScroll) { mx += 3; if (mx > getWidth()) { mx = (int) -paint.measureText("百度百科"); } } } }
四、通过代码添加自定义控件。
setContentView(new MyView(this));
相关文章推荐
- tomcat7.0.59对el取消过滤java关键字的设置
- iOS中关于UItableview中代理heightForRowAtIndexPath调用次数和顺序的系统差异性
- Openwrt 广告植入
- 网狐棋牌(六) DataBaseEngine 和 网狐棋牌(七) CEventService
- Linus 又发怒了,针对丑陋的代码
- 低功耗蓝牙4.0BLE编程-nrf51822开发(11)-蓝牙串口代码分析
- hadoop、hbase源码编译
- Objective-C中变量采用@property的各个属性值的含义
- 网狐棋牌(五) TCPSocketEnging分析
- VB操作EXCEL文件大全
- 错误编码 = 17
- mysql中难以理解的sql
- 在VS2010上使用C#调用非托管C++生成的DLL文件(图文讲解)
- Codevs_P1378 选课(树形DP+分组背包)
- java使用wkhtmltopdf实现Html转pdf,并在centos服务器部署步骤。
- android SpannableString与SpannableStringBuilder
- Android stuido和Intellij支持Eclipse的代码格式化文件
- 没有准备!跳槽岂是那么容易的事?
- 网狐棋牌(四) TimerEngine
- x86、i386、i486、i586、i686和x86_64