自定义气泡背景
来源:互联网 发布:采购数据报告体现 编辑:程序博客网 时间:2024/04/30 03:18
这个就是一个自定义View,其实自定义View也就是重写那么几个方法,onDraw(),onMeasure()。还是直接来看代码吧,注视里面都有的
public class CircleView extends View { private int circleSum;//圆的数量 private int circleRadio;//圆的半径 private int circleColor;//圆的颜色 private int backColor;//背景颜色 private Paint backPaint;//背景画笔 private Paint circlePaint;//圆的画笔 private Circle[] circles; private int[] direction = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; private Random random; private float width; private float height; private int[] location = new int[2]; private MyThread mMyThread; private boolean running = true; public CircleView(Context context) { super(context); backPaint = new Paint(); init(); } public CircleView(Context context, AttributeSet attrs) { super(context, attrs); TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CircleView); circleSum = ta.getInteger(R.styleable.CircleView_circleSum, 10); circleColor = ta.getColor(R.styleable.CircleView_circleColor, Color.parseColor("#7756ffff")); backColor = ta.getColor(R.styleable.CircleView_backColor, Color.parseColor("#21efef")); circleRadio = ta.getInteger(R.styleable.CircleView_circleRadio, 60); ta.recycle(); init(); } /** * 初始化画笔 */ private void init() { backPaint = new Paint(); backPaint.setColor(backColor); circlePaint = new Paint(); circlePaint.setColor(circleColor); } /** * 比onDraw先执行 * <p/> * 一个MeasureSpec封装了父布局传递给子布局的布局要求,每个MeasureSpec代表了一组宽度和高度的要求。 * 一个MeasureSpec由大小和模式组成 * 它有三种模式:UNSPECIFIED(未指定),父元素部队自元素施加任何束缚,子元素可以得到任意想要的大小; * EXACTLY(完全),父元素决定自元素的确切大小,子元素将被限定在给定的边界里而忽略它本身大小; * AT_MOST(至多),子元素至多达到指定大小的值。 * <p/> * 它常用的三个函数: * 1.static int getMode(int measureSpec):根据提供的测量值(格式)提取模式(上述三个模式之一) * 2.static int getSize(int measureSpec):根据提供的测量值(格式)提取大小值(这个大小也就是我们通常所说的大小) * 3.static int makeMeasureSpec(int size,int mode):根据提供的大小值和模式创建一个测量值(格式) */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); //获取控件宽度 width = getMeasuredWidth(); //获取控件高度 height = getMeasuredHeight(); //获取控件相对于父控件的位置坐标 this.getLocationInWindow(location); //初始化圆 initCircle(); } /** * 初始化圆 */ private void initCircle() { circles = new Circle[circleSum]; random = new Random(); for (int i = 0; i < circleSum; i++) { int d = random.nextInt(direction.length); int x = random.nextInt((int) width); int y = random.nextInt((int) height); circles[i] = new Circle(x, y, d); } } @Override protected void onDraw(Canvas canvas) { //绘制背景 canvas.drawRect(0, 0, location[0] + width, location[1] + height, backPaint); //遍历绘制每一个圆 for (Circle c : circles) { canvas.drawCircle(c.getX(), c.getY(), circleRadio, circlePaint); } if (mMyThread == null) { mMyThread = new MyThread(); mMyThread.start(); } } /** * 不在窗口显示的时候停止线程 */ @Override protected void onDetachedFromWindow() { running = false; super.onDetachedFromWindow(); } class MyThread extends Thread { @Override public void run() { while (running) { for (int i = 0; i < circleSum; i++) { Circle c = circles[i]; changeDirection(c); //超出边界后重置方向 if (c.getX() > width || c.getX() < 0 || c.getY() > height || c.getY() < 0) { int d; while (true) { d = random.nextInt(direction.length); int lastD = c.getDirection(); if ((lastD == 0 || lastD == 4 || lastD == 6 || lastD == 8 || lastD == 10) && (d == 0 || d == 4 || d == 6 || d == 8 || d == 10)) {//上 continue; } else if ((lastD == 1 || lastD == 5 || lastD == 7 || lastD == 9) && (d == 1 || d == 5 || d == 7 || d == 9)) {//下 continue; } else if ((lastD == 2 || lastD == 4 || lastD == 5 || lastD == 8 || lastD == 9) && (d == 2 || d == 4 || d == 5 || d == 8 || d == 9)) {//左 continue; } else if ((lastD == 3 || lastD == 6 || lastD == 7 || lastD == 10) && (d == 3 || d == 6 || d == 7 || d == 10)) {//右 continue; } break; } circles[i].setDirection(d); } } try { Thread.sleep(30); } catch (InterruptedException e) { e.printStackTrace(); } postInvalidate(); } } private void changeDirection(Circle c) { float dx = 0.3f; switch (c.getDirection()) { case 0://上 c.setY(c.getY() - dx); break; case 1://下 c.setY(c.getY() + dx); break; case 2://左 c.setX(c.getX() - dx); break; case 3://右 c.setX(c.getX() + dx); break; case 4://左上 c.setX(c.getX() - dx); c.setY(c.getY() - dx); break; case 5://左下 c.setX(c.getX() - dx); c.setY(c.getY() + dx); break; case 6://右上 c.setX(c.getX() + dx); c.setY(c.getY() - dx); break; case 7://右下 c.setX(c.getX() + dx); c.setY(c.getY() + dx); break; case 8://左上 c.setX(c.getX() - dx); c.setY(c.getY() - dx * 2); break; case 9://左下 c.setX(c.getX() - dx * 2); c.setY(c.getY() + dx); break; case 10://右上 c.setX(c.getX() + dx); c.setY(c.getY() - dx * 2); break; } } } class Circle { private float x; private float y; private int direction; public Circle(float x, float y, int d) { this.x = x; this.y = y; this.direction = d; } public float getX() { return x; } public void setX(float x) { this.x = x; } public void setY(float y) { this.y = y; } public float getY() { return y; } public void setDirection(int direction) { this.direction = direction; } public int getDirection() { return direction; } } }
来看看在xml文件中怎么使用
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <com.tianzhao.myapplication.CircleView xmlns:cv="http://schemas.android.com/apk/res/com.tianzhao.myapplication" //自己的命名空间 android:layout_width="fill_parent" android:layout_height="200dp" cv:circleSum="10" //圆的数量 cv:circleColor="#7756ffff" //圆的颜色 cv:backColor="#21efef"/> //背景颜色 <RelativeLayout android:layout_width="fill_parent" android:layout_height="200dp"> <ImageView android:id="@+id/iv" android:layout_width="80dp" android:layout_height="80dp" android:layout_centerInParent="true" android:background="@drawable/user" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/iv" android:layout_centerHorizontal="true" android:layout_marginTop="5dp" android:text="登录" android:textSize="20dp" /> </RelativeLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="40dp" android:layout_centerHorizontal="true" android:layout_marginTop="230dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center_vertical" android:text="用户名:" android:textSize="20dp" /> <EditText android:layout_width="200dp" android:layout_height="wrap_content" android:layout_marginLeft="5dp" android:gravity="center_vertical" /> </LinearLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="40dp" android:layout_centerHorizontal="true" android:layout_marginTop="280dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center_vertical" android:text="密 码:" android:textSize="20dp" /> <EditText android:layout_width="200dp" android:layout_height="wrap_content" android:layout_marginLeft="5dp" android:gravity="center_vertical" /> </LinearLayout> </RelativeLayout>
这里会涉及到一个attr.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="CircleView"> <attr name="circleSum" format="integer"></attr> <attr name="circleColor" format="color"></attr> <attr name="backColor" format="color"></attr> <attr name="circleRadio" format="integer"></attr> </declare-styleable> </resources>
阅读全文
0 0
- 自定义气泡背景View
- 自定义气泡背景
- 自定义气泡文字背景上下边距总是宽
- 仿微信聊天记录气泡背景
- 自定义气泡文字背景遇到的上下边距比较宽的问题
- 百度地图自定义气泡
- 百度地图自定义气泡
- 自定义气泡菜单
- iOS 自定义绘制气泡
- 自定义气泡提示小插件
- cesium自定义气泡窗口infoWindow
- 自定义气泡,适配项目中的所有气泡
- 自定义背景
- 气泡
- 气泡
- 气泡
- iOS 自定义百度地图标注气泡
- 百度地图自定义弹出气泡和大头针
- ubuntu下如何操作Mysql数据库(增、删、改、查)
- 抽象类、接口的深入理解
- xss测试题的小总结
- android通过浏览器直接调用url
- linux关于bashrc与profile的区别(转)
- 自定义气泡背景
- 快速排序
- Shiro入门学习六
- hduoj 2007
- bzoj2599 [IOI2011]Race(定权值最短树上路径)
- 基于cubietruck的嵌入式系统移植
- linux下phpstudy如何使用
- 事务一致性 与异常抛出
- C语言中gets()和scanf()的区别