自定义View之案列篇(一):魔方
来源:互联网 发布:乐视max2 root软件 编辑:程序博客网 时间:2024/06/01 09:18
首先给各位道个歉,公司加班已有两个多月,博客也迟迟没有更新。还非常感谢认真阅读博客并提出错误的地方的童鞋,我也非常鼓励这种做法,对任何有疑问的地方,大胆提出。给你们点个赞。
老规矩,先来看看魔方的效果图:
学习博客也是学习一种变通的思想,能够举一反三,才能掌握真正的精髓。
这里留下一个小小的挑战:
怎么获取菱形区域的点击区域?文章后面我给出了解决方案,不知道你是否有更好的方案呢?
魔方布局(BlockFrameLayout)
分析效果图,可以看出魔方布局是由一块块小的菱形按照某种规律组合而成的,我们这里以繁化简,先来看看一块小的菱形:
接着看看三块菱形组成的图案:
看看最后的效果图:
是不是已经发现规律了啊?对的,以三块菱形为一组,从上往下就组成了最终的图案。
核心思想:分析前三块菱形和后三块菱形的坐标变化。
相信你已经找到了:
if ((i + 1) % 3 == 1) { //第一块 startX = getWidth() / 2 - mChildSize / 2; startY = mChildSize * bulge; } else if ((i + 1) % 3 == 2) { //第二块 startX = getWidth() / 2 - mChildSize; startY = mChildSize * bulge + mChildSize / 2; } else if ((i + 1) % 3 == 0) { //第三块 startX = getWidth() / 2; startY = mChildSize * bulge + mChildSize / 2; bulge++; }
那么 onLayout 方法:
final int childCount = getChildCount(); int startX = 0; int startY = 0; int bulge = 0; for (int i = 0; i < childCount; i++) { View childView = getChildAt(i); if (childView.getVisibility() == GONE) { continue; } if ((i + 1) % 3 == 1) { startX = getWidth() / 2 - mChildSize / 2; startY = mChildSize * bulge; } else if ((i + 1) % 3 == 2) { startX = getWidth() / 2 - mChildSize; startY = mChildSize * bulge + mChildSize / 2; } else if ((i + 1) % 3 == 0) { startX = getWidth() / 2; startY = mChildSize * bulge + mChildSize / 2; bulge++; } childView.layout(startX, startY, startX + mChildSize, startY + mChildSize); }
如果对于自定义 ViewGroup 流程有什么疑问的童鞋,请查看我自定义系类前面的几篇博客。文章后面会给出源码。
菱形(BlockView )
BlockView 类比较简单,主要看看 onDraw 方法的实现:
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPath.reset(); mPath.moveTo(getWidth() / 2, 0); mPath.lineTo(0, getHeight() / 2); mPath.lineTo(getWidth() / 2, getHeight()); mPath.lineTo(getWidth(), getHeight() / 2); mPath.close(); canvas.drawPath(mPath, mPaint); mTextPaint.setTextSize(getWidth() / 4); mMetrics = mTextPaint.getFontMetrics(); mTextPaint.setTextAlign(Paint.Align.CENTER); canvas.drawText(mText, getWidth() / 2, getHeight() / 2 + (mMetrics.bottom - mMetrics.top) / 2 - mMetrics.bottom, mTextPaint); }
其实就是绘制了一个路径,那么怎么来获取这个菱形区域的点击事件呢?
你肯定会想到重写 onTouchEvent(触摸事件) 方法?不过这里又有一个疑问,View 跟 View 之间有重叠的部分,onTouchEvent 方法返回 true(消费事件) 可能会引起下层的 View 的点击事件失效?
最后 onTouchEvent 方法返回默认的值:
return super.onTouchEvent(event);
这样只会执行 MotionEvent.ACTION_DOWN
分支,那么我在 ACTION_DOWN
添加接口,不就实现了不规则路径的点击事件吗。
思路给出了,下面来看看代码:
@Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: float x = event.getX(); float y = event.getY(); Region region = new Region(); region.setPath(mPath, new Region(0, 0, getWidth(), getHeight())); if (mOnClickListener != null) { if (region.contains((int) x, (int) y)) { mOnClickListener.BlockOnClickListener(mText); //mClickEnable = false; } } break; } return super.onTouchEvent(event); }
源码地址。
- 自定义View之案列篇(一):魔方
- 自定义View(一)之初识自定义View
- android自定义view之地图(一)
- 自定义View之文字游乐场(一)
- Android进阶之自定义view(一)
- 【Android进阶之自定义View(一)】
- android 自定义view之概述(一)
- 自定义View之QQ小红点(一)
- 自定义View之入门(一)
- android 自定义view之(一) Creating a View Class
- Android开发之自定义View专题(一):自定义柱形图
- 自定义view之自定义折线图(一)
- 自定义View 之 ImageView(一) 自定义圆形ImageView
- 自定义View(一)
- 自定义view(一)
- 自定义View(一)
- 自定义View(一)
- 自定义View(一)
- 【PAT甲级】1024. Palindromic Number (25)
- FROM_UNIXTIME 格式化MYSQL时间戳函数
- 计算连板价
- Android 源码系列之<十一>从源码的角度深入理解AccessibilityService,打造自己的APP小外挂(下)
- Spring 配置使用 - AOP 通知参数
- 自定义View之案列篇(一):魔方
- mysql在dos窗口下的原生使用
- 禁用右键
- Mysql利用Navicat导入导出表
- 台大林轩田机器学习课程笔记4----训练 VS. 测试
- Android线程池
- 华为路由器添加端口映射(带范围NAT)
- 文档
- 高仿新闻类APP频道管理功能,ItemTouchHelper的实践