当我们想展示一个数组形式的数据的时候,要么是使用列表的形式,要么是使用网格的形式,今天我们介绍一种奇葩的形式,圆圈形式:

注意,周边的扇形是可以点击的。如果使用现有控件,要实现起来是有难度的,所以我们就采用了自定义View的方式。

下面是原理以及使用方法,整个项目可以到这里下载:https://github.com/jianghejie/GossipView

绘制

主要是外部扇形以及内部圆圈背景的绘制,最里面其实还有个很细的圆圈,那个其实是用在当想显示加载效果的时候,但这不是重点略去不讲。

内部圆圈背景的绘制很简单直接使用Drawable 的draw方法,前提是先设置好bounds(下面会讲到).

mInnerBackGroud.draw(canvas);

而外部扇形的绘制是分别调用drawArc方法(也许应该取别的名字,和canvas的方法冲突了)完成的:

for(int i = 0;i < mPieceNumber ; i++){drawArc(i , canvas);
}

有多少个扇形调用多少次。

drawArc定义如下:

/** 按索引值绘制扇区,第一个扇区的中心位于3点钟方向*/
public void drawArc(int index , Canvas canvas){int startdegree  =  mPieceDegree * (index) - (mPieceDegree - mDividerDegree) / 2;if(index == mSelectIndex){mOuterArcPaint.setColor(0xFFcacccc);}else{mOuterArcPaint.setColor(outArcColor[index]);}float radious  = ((float)mWidth - (float)outArctrokeWidth) / 2 - padding ;float midDegree = startdegree + ( mPieceDegree  - mDividerDegree) /2 ;double x  = radious * Math.cos(midDegree * Math.PI/180);double y  = radious * Math.sin(midDegree  * Math.PI/180);x = x + getOriginal().x;y = y + getOriginal().y;canvas.drawArc(mOuterArcRectangle, startdegree, mPieceDegree  - mDividerDegree, false, mOuterArcPaint);Rect rect = new Rect();mOuterTextPaint.getTextBounds(items.get(index).getTitle(), 0, items.get(index).getTitle().length(), rect);int txWidth  = rect.width();int txHeight = rect.height();canvas.drawText(items.get(index).getTitle(), (int)x - txWidth/2, (int)y + txHeight/2, mOuterTextPaint);
}

空间计算:

根据onMeasure方法中的宽和高计算出不同区域的基本参 数,比如外扇形的厚度outArctrokeWidth,外扇形文字的大小mOuterTextPaint,外扇形的半径 mOuterArcRadius,外扇形绘制的矩形区域mOuterArcRectangle;以及内部圆圈mInnerBackGroud的 bounds。

按下效果:

外部扇形的按下效果是根据不同状态下设置画笔的颜色来实现的:

如果某一个扇形的索引刚好等于选中的mSelectIndex,则设置按下的颜色:

if(index == mSelectIndex){mOuterArcPaint.setColor(0xFFcacccc);
}else{mOuterArcPaint.setColor(outArcColor[index]);
}

而内部的圆圈部分则直接采用selector图片的方式:

if(mSelectIndex == -1){Log.i(TAG,"mSelectIndex = "+mSelectIndex);mInnerBackGroud.setState(PRESSED_FOCUSED_STATE_SET);
}else{mInnerBackGroud.setState(EMPTY_STATE_SET);
}

mSelectIndex == -1 表示选中的是最中间的圆圈,若为真设置Drawable mInnerBackGroud的状态为PRESSED_FOCUSED_STATE_SET,反之为EMPTY_STATE_SET,因为 mInnerBackGroud其实是由selector得来的Drawable ,所以只要设置了不同的状态就会绘出不同的图片效果。

另外为了处理扇形和内部圆圈的按下效果,我们必须判断当前到底是点中了那部分

@Override
public boolean onTouchEvent(MotionEvent event) {if(event.getAction() == MotionEvent.ACTION_DOWN) {mSelectIndex = getTouchArea(new Point(event.getX() , event.getY()));this.invalidate();Log.i(TAG ,"mSelectIndex =" +mSelectIndex);//mSelectIndex = -1;}else if(event.getAction() == MotionEvent.ACTION_UP && event.getAction() != MotionEvent.ACTION_CANCEL){int upIndex = getTouchArea(new Point(event.getX() , event.getY()));if(mListener != null){mListener.onPieceClick(upIndex);}mSelectIndex = -2;this.invalidate();}else if(event.getAction() == MotionEvent.ACTION_CANCEL){mSelectIndex = -2;this.invalidate();}return true;
}

在ACTION_DOWN事件中,调用getTouchArea来判断当前选中的是什么,getTouchArea可能返回的有三种值:

-1 选中的是最中间的圆圈

-2 选中的是扇形之间的间隔部分

整数:选中的是某个扇形。

ACTION_UP事件发生之后我们通知UI重绘,并且调用onPieceClick通知注册的Lisetner我选择了什么。

 

监听选中了什么

GossipView.OnPieceClickListener

public interface OnPieceClickListener {void onPieceClick(int whitchPiece);
}

这个不用解释了吧,最常见的观察者模式。

下面是使用方法:

xml中:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"tools:context="com.jcodecraeer.gossipview.MainActivity" ><com.jcodecraeer.gossipview.GossipViewandroid:id="@+id/gossipview"android:layout_width="fill_parent"android:layout_height="fill_parent" />
</RelativeLayout>

Activity中:

...GossipView gossipView = (GossipView)findViewById(R.id.gossipview);String [] strs = {"安卓","微软","苹果","谷歌","百度","腾讯"} ;final List<GossipItem> items =new ArrayList<GossipItem>();for(int i = 0; i < strs.length; i++) {GossipItem item = new GossipItem(strs[i],3);items.add(item);}gossipView.setItems(items);gossipView.setNumber(3);gossipView.setOnPieceClickListener( new GossipView.OnPieceClickListener(){@Overridepublic void onPieceClick(int index) {if(index != -1 &&  index != -2) {Toast.makeText(MainActivity.this, "你选择了" + items.get(index).getTitle(), 300).show();}}});
....

GossipItem的定义:

package com.jcodecraeer.gossipview;
public class GossipItem  {private String title;private int index;public GossipItem (String title,int index){this.title =title;this.index = index;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public int getIndex() {return index;}public void setIndex(int index) {this.index = index;}
}

转载自:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/1115/1986.html

转载于:https://www.cnblogs.com/noodlesonce/p/4099001.html

GossipView:圆圈布局的自定义view相关推荐

  1. android 六边形布局,Android自定义View——一个可定制的六边形阵列

    关于六边形的自定义View网上已经有很多了,但目前来看都是固化的UI,可定制性不高,所以我这里将六边形与坐标绑定,这样的话我们就可以随意组合六边形形成我们需要的一个图案. 基本思路也很简单,一句话-- ...

  2. android 开发打赏布局,Android自定义View模仿虎扑直播界面的打赏按钮功能

    Android自定义View模仿虎扑直播界面的打赏按钮功能 发布时间:2020-09-28 12:15:53 来源:脚本之家 阅读:77 作者:shenhuniurou 前言 作为一个资深篮球爱好者, ...

  3. android 环绕布局,Android自定义View实现圆形环绕效果

    之前项目中需要实现一个四周环绕中心圆形头像的效果,感觉还是自定义比较方便,于是就自己封装了一个控件去实现.先贴张图显示最终效果. 首先自定义一个View继承自LinearLayout,通过动态添加ch ...

  4. android 自定义音乐圆形进度条,Android自定义View实现音频播放圆形进度条

    本篇文章介绍自定义View配合属性动画来实现如下的效果 实现思路如下: 根据播放按钮的图片大小计算出圆形进度条的大小 根据音频的时间长度计算出圆形进度条绘制的弧度 通过Handler刷新界面来更新圆形 ...

  5. android 画布实现签名,Android 自定义View手写签名并保存图片

    1.自定义View--支撑设置画笔色彩,画笔宽度,画板色彩,铲除画板,查看是否有签名,保存画板图片(仿制粘贴可直接使用) /***CreatedbyYyyyQon2020/3/5. *电子签名*/pu ...

  6. java 手写签名_Android 自定义View手写签名并保存图片

    GIF压缩有问题,运行很顺滑!!! 1.自定义View--支持设置画笔颜色,画笔宽度,画板颜色,清除画板,检查是否有签名,保存画板图片(复制粘贴可直接使用) /*** Created by YyyyQ ...

  7. Android自定义View之图形图像(模仿360的刷新球自定义一个SeekBar)

    概述: 360安全卫士的那个刷新球(姑且叫它刷新球,因为真的不知道叫什么好,不是dota里的刷新球!!),里面像住了水一样,生动可爱,看似简单,写起来不太简单,本例程只是实现了它的部分功能而已,说实话 ...

  8. 面试:自定义view / viewgroup 相关问题

    Q:列举一个自定义view的例子,流式布局: 自定义View 实现流式布局FlowLayout - 简书 Android 自定义流式布局FlowLayout 自己造的轮子真香!_卤蛋还是茶叶蛋的博客- ...

  9. 自定义View的三种实现方式及自定义属性使用介绍

    自定义View的三种实现方式及自定义属性使用介绍 一 前言 二 三种自定义控件的方法 2.1 组合控件 2.2 继承控件 2.2.1 继承View类系统控件 2.2.2 继承ViewGroup类系统控 ...

最新文章

  1. android apk签名工具_关于keytool和jarsigner工具签名的使用小结
  2. 你所不知道的 Android Studio 调试技巧
  3. linux用户态驱动--IOMMU(三)
  4. djangoORM数据类型及基本操作
  5. c# 中的as,is
  6. Preparing Cities for Robot Cars【城市准备迎接自动驾驶汽车】
  7. Function(函数)
  8. 【Redis】Redis替代方案
  9. Java改环境变量把path修改了,CentOS查看和修改PATH环境变量的方法
  10. c++ primer plus(第6版)中文版 第十二章编程练习答案
  11. C++中#includeXXX.h和#includeXXX.h的区别
  12. yahoo也推出站点统计了
  13. [Python] jieba库?结巴库?
  14. CC2530按键控制呼吸灯
  15. 独家研究 I 某新一线城市中高端养老社区项目(CCRC)入住客户画像深度洞察研究报告
  16. c++小游戏 走迷宫
  17. html js css 简明教程,HTML+CSS+JavaScript网页制作简明教程
  18. Nazo前三十三关攻略
  19. Python学习 Day26 JS循环语句(二)
  20. 每个程序员都应该阅读的最有影响力的书是什么?

热门文章

  1. php header函数的详解,php header函数的详解_PHP教程
  2. 文本预处理之判断是否包含非法字符或非英文字符(Java)
  3. oracle oms可以调用吗,oracle oms
  4. oracle必备文件,oracle初学者必备基础
  5. python导入同一文件夹下的类_Python模块导入机制与规范
  6. python打印一个对象的所有属性_python打印出所有的对象/模块的属性代码详解
  7. lm opencv 算法_相机模型与标定(七)--LM算法在相机标定中的使用
  8. php fatal error 500,PHP在Linux下出现HTTP ERROR 500解决方法
  9. 最长上升子序列_动态规划 最长上升子序列LIS
  10. ubuntu20下lnmp环境nextcloud安装