zoukankan      html  css  js  c++  java
  • 51、自定义View基础和原理

    一、编写自己的自定义View
    最简单的自定义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);
        }
    
    }

    二、加入逻辑线程
    让文字动起来,改变坐标
    在线程中修改坐标(加入循环,时间睡眠)
    重新绘制元素(两种方式)
    线程休眠时间控制(去除逻辑处理时间)

     1 import java.util.Random;
     2 import android.content.Context;
     3 import android.graphics.Canvas;
     4 import android.graphics.Paint;
     5 import android.graphics.RectF;
     6 import android.util.AttributeSet;
     7 import android.view.View;
     8 
     9 public class LogicView extends View {
    10 
    11     // 实例化 画笔。
    12     private Paint paint = new Paint();
    13     // 
    14     private float rx = 0;
    15     // 添加线程属性
    16     private MyThread thread;
    17     /**
    18      * 绘制在文字下,30的地方。
    19      * RectF(float left, float top, float right, float bottom)
    20      *         0           30+30                宽度100       60+100
    21      */
    22     private RectF rectF = new RectF(0, 60, 100, 160);
    23     // 区间角度
    24     private float sweepAngle = 0;
    25 
    26     // 在布局当中使用。
    27     public LogicView(Context context, AttributeSet attrs) {
    28         super(context, attrs);
    29     }
    30 
    31     // 在代码当中使用。
    32     public LogicView(Context context) {
    33         super(context);
    34     }
    35 
    36     @Override
    37     protected void onDraw(Canvas canvas) {
    38         paint.setTextSize(30);
    39         canvas.drawText("LogicView", rx, 30, paint);
    40         /**
    41          * 绘制一个圆。
    42          * drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,
    43               Paint paint)
    44          * sweepAngle:区间角度。
    45          * useCenter:true ,false. 绘制的效果不同。
    46          */
    47         canvas.drawArc(rectF, 0, sweepAngle, true, paint);
    48 
    49         if (thread == null) {
    50             thread = new MyThread();
    51             thread.start();
    52         }
    53     }
    54 
    55     class MyThread extends Thread {
    56         // 随机对象,产生随机值。
    57         Random rand = new Random();
    58         @Override
    59         public void run() {
    60             while (true) {
    61                 rx += 3;
    62                 // 当超出屏幕的宽度时。
    63                 if (rx > getWidth()) {
    64                     /**
    65                      * 走出屏幕后,重新回到屏幕。
    66                      * 0 - 文字的宽度,这样 “LogicView”文字,从左边出来的时候,
    67                      * 就可以从w开始一点点移出屏幕。
    68                      */
    69                     rx = 0 - paint.measureText("LogicView");
    70                 }
    71 
    72                 sweepAngle++;
    73                 if (sweepAngle > 360) {
    74                     sweepAngle = 0;
    75                 }
    76 
    77                 // 取到 0-255的随机数。
    78                 int r = rand.nextInt(256);
    79                 int g = rand.nextInt(256);
    80                 int b = rand.nextInt(256);
    81 
    82                 // 设置颜色。
    83                 paint.setARGB(255, r, g, b);
    84 
    85                 postInvalidate(); // 重绘
    86                 try {
    87                     Thread.sleep(30); // 睡眠30毫秒
    88                 } catch (InterruptedException e) {
    89                     e.printStackTrace();
    90                 }
    91             }
    92         }
    93     }
    94 
    95 }

    把以上代码进行封装。

    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();
                    }
                }
            }
        }
    
    }
     1 import java.util.Random;
     2 import android.content.Context;
     3 import android.graphics.Canvas;
     4 import android.graphics.Paint;
     5 import android.graphics.RectF;
     6 import android.util.AttributeSet;
     7 
     8 public class LogicView extends BaseView {
     9 
    10     private Paint paint = new Paint();
    11     private float rx = 0;
    12     private RectF rectF = new RectF(0, 60, 100, 160);
    13     private float sweepAngle = 0;
    14     Random rand = new Random();
    15 
    16     public LogicView(Context context, AttributeSet attrs) {
    17         super(context, attrs);
    18     }
    19 
    20     public LogicView(Context context) {
    21         super(context);
    22     }
    23 
    24     @Override
    25     protected void drawSub(Canvas canvas) {
    26         paint.setTextSize(30);
    27         canvas.drawText("LogicView", rx, 30, paint);
    28         canvas.drawArc(rectF, 0, sweepAngle, true, paint);
    29     }
    30 
    31     @Override
    32     protected void logic() {
    33         rx += 3;
    34 
    35         if (rx > getWidth()) {
    36             rx = 0 - paint.measureText("LogicView");
    37         }
    38 
    39         sweepAngle++;
    40         if (sweepAngle > 360) {
    41             sweepAngle = 0;
    42         }
    43 
    44         int r = rand.nextInt(256);
    45         int g = rand.nextInt(256);
    46         int b = rand.nextInt(256);
    47 
    48         paint.setARGB(255, r, g, b);
    49     }
    50 
    51 }
    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));

  • 相关阅读:
    codevs 1576 最长严格上升子序列
    codevs 3415 最小和
    codevs 2102 石子归并 2
    洛谷 P1040 加分二叉树
    BZOJ 3038 上帝造题的七分钟二
    codevs 线段树练习ⅠⅡⅢ
    启动Tomcat提示:指定的服务未安装
    poj 1061 青蛙的约会 (扩展欧几里得模板)
    POJ 3449 Geometric Shapes(判断几个不同图形的相交,线段相交判断)
    HDU 5251 矩形面积(二维凸包旋转卡壳最小矩形覆盖问题) --2015年百度之星程序设计大赛
  • 原文地址:https://www.cnblogs.com/androidsj/p/4935115.html
Copyright © 2011-2022 走看看