使用SVG打造不规则自定义控件
作者:互联网
传统的ImageButtom图片等控件都是基于长方形等规则图形,若是想使用不规则图形,则可以使用SVG图片定义Path路径,从而打造不规则图形,代码如下:
public class ChinaMap extends View {
//初始化画笔
private Paint paint;
private Context context;
private ProviceItem select;
//装中国地图的Rectf
private RectF totalRect;
List<ProviceItem> itemList;
//地图缩放比例
private float scale =1.0f;
//省份颜色
int[] colorArray = new int[]{0xFF239BD7, 0xFF30A9E5, 0xFF80CBF1, 0xFFFFFFFF};
//表示SVG图片是否解析完成
private boolean isEnd;
public ChinaMap(Context context) {
super(context);
}
public ChinaMap(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}
public ChinaMap(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private void init(Context context) {
this.context = context;
paint = new Paint();
paint.setAntiAlias(true);
loadThread.start();
}
private Thread loadThread = new Thread(new Runnable() {
@Override
public void run() {
//定义一个输入流去解析xml
InputStream input = context.getResources().openRawResource(R.raw.china);
//定义一个封装所有省份的集合
List<ProviceItem> list = new ArrayList<>();
//获取到解析器的工厂类
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = null;
try {
documentBuilder = factory.newDocumentBuilder();
//获取到SVG的XML对象
Document parse = documentBuilder.parse(input);
//获取所有节点根目录
Element element = parse.getDocumentElement();
//通过Element获取所有path节点的集合
NodeList nodeList = element.getElementsByTagName("path");
//定义四个点,记录中国地图两个点坐标
float left = -1;
float top = -1;
float right = -1;
float bottom = -1;
//遍历所有的path节点
for(int i=0;i<nodeList.getLength();i++){
//获取到每个节点
Element item = (Element) nodeList.item(i);
String pathData = item.getAttribute("android:pathData");
Path path = PathParser.createPathFromPathData(pathData);
ProviceItem proviceItem = new ProviceItem(path);
list.add(proviceItem);
//初始化省份Rect
RectF rect = new RectF();
path.computeBounds(rect,true);
//初始化中国地图两个点坐标
//获取到left最小的值
left = left == -1 ? rect.left:Math.min(left,rect.left);
top = top == -1 ? rect.top:Math.min(top,rect.top);
right = right == -1 ? rect.right:Math.max(right,rect.right);
bottom = bottom == -1 ? rect.bottom:Math.max(bottom,rect.bottom);
}
//封装中国地图
totalRect = new RectF(left,top,right,bottom);
itemList = list;
//绘制中国地图
weakReference.get().sendEmptyMessage(1);
} catch (Exception e) {
e.printStackTrace();
}
}
});
private Handler handler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
if(itemList == null || itemList.size()<=0){
return;
}
//给省份设置颜色
// if(msg.what == 1){
for(int i=0;i<itemList.size();i++){
ProviceItem proviceItem = itemList.get(i);
proviceItem.setDrawColor(colorArray[i%4]);
}
//}
//xml解析完毕
isEnd = true;
//设置缩放比例
measure(getMeasuredWidth(),getMeasuredHeight());
//调用绘制
postInvalidate();
}
};
private WeakReference<Handler> weakReference = new WeakReference(handler);
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//获取到当前控件的宽高
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
if(!isEnd){
setMeasuredDimension(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(height , MeasureSpec.EXACTLY));
return;
}
if(totalRect != null){
//获取地图的宽度
double mapWidth = totalRect.width();
scale = (float) (width/mapWidth);
}
setMeasuredDimension(MeasureSpec.makeMeasureSpec(width,MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(height,MeasureSpec.EXACTLY));
}
@Override
protected void onDraw(Canvas canvas) {
if(!isEnd){
return;
}
if(itemList != null && itemList.size() > 0){
canvas.save();
//设置缩放比例
canvas.scale(scale,scale);
for(int i=0;i<itemList.size();i++){
itemList.get(i).drawItem(canvas,paint,itemList.get(i)==select);
}
}
super.onDraw(canvas);
}
//处理触摸事件
@Override
public boolean onTouchEvent(MotionEvent event) {
if(itemList ==null || itemList.size() ==0) {
return true;
}
//选出被触摸的省份
if(itemList != null && itemList.size() !=0){
for(ProviceItem item :itemList){
if(item.isTouch(event.getX()/scale,event.getY()/scale)){
select = item;
}
}
//若存在被触摸的省份,则重新绘制
if(select != null){
postInvalidate();
}
}
return super.onTouchEvent(event);
}
}
加载结果:
当点击图片中某个省份时,结果如下:
标签:控件,自定义,int,SVG,private,itemList,context,new,rect 来源: https://blog.csdn.net/qq_41672484/article/details/115150780