Android自定義控件實(shí)現(xiàn)不規(guī)則區(qū)域點(diǎn)擊事件
本文實(shí)例為大家分享了Android實(shí)現(xiàn)不規(guī)則區(qū)域點(diǎn)擊事件的具體代碼,供大家參考,具體內(nèi)容如下
先看看效果

對(duì)于上面的圖形實(shí)現(xiàn)主要用到svg,通過(guò)解析svg獲取不規(guī)則的圖形,對(duì)于svg文件這個(gè)一般需要美工提供,不需要我們開(kāi)發(fā)實(shí)現(xiàn)。
實(shí)現(xiàn)上面效果第一步是解析svg文件代碼如下
package demo.zjd.com.taiwandemo.utils;
import android.graphics.RectF;
import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import demo.zjd.com.taiwandemo.bean.CityPath;
import demo.zjd.com.taiwandemo.bean.ViewAttr;
import demo.zjd.com.taiwandemo.calback.ParserCallBack;
/**
* Created by zhangjd on 2017/6/1.
* 解析svg xml
*/
public class SVGXmlParserUtils {
public static void parserXml(final InputStream in, final ParserCallBack mParserCallBack){
new Thread(new Runnable() {
@Override
public void run() {
List<CityPath> list=new ArrayList<>();
ViewAttr mViewAttr=new ViewAttr();
parserXml(in,list,mViewAttr);
if(mParserCallBack!=null){
mParserCallBack.callback(list,mViewAttr);
}
}
}).start();
}
private static void parserXml(InputStream in, List<CityPath> list, ViewAttr mViewAttr){
XmlPullParser parser = Xml.newPullParser();
RectF mRectF=new RectF();
try {
parser.setInput(in, "UTF-8");
int eventType = parser.getEventType();
String name = null;
CityPath mCityPath = null;
list.clear();
while (eventType != XmlPullParser.END_DOCUMENT) {
switch (eventType) {
case XmlPullParser.START_DOCUMENT:// 文檔開(kāi)始事件,可以進(jìn)行數(shù)據(jù)初始化處理
break;
case XmlPullParser.START_TAG:// 開(kāi)始元素事件
name = parser.getName();
if ("path".equals(name)) {
mCityPath = new CityPath();
mCityPath.setId(parser.getAttributeValue(null, "id"));
mCityPath.setTitle(parser.getAttributeValue(null, "title"));
mCityPath.setPathData(parser.getAttributeValue(null, "d"));
}
break;
case XmlPullParser.END_TAG:// 結(jié)束元素事件
name = parser.getName();
if ("path".equals(name)) {//這個(gè)地方主要處理屏幕適配問(wèn)題,后面后詳細(xì)講解
mCityPath.initPath();
//處理path的邊界
//計(jì)算控制點(diǎn)的邊界
mCityPath.getmPath().computeBounds(mRectF, true);
mViewAttr.colSize(mRectF);
list.add(mCityPath);
}
break;
}
eventType = parser.next();
}
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(in!=null){
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
解析完svg文件之后就是繪制圖像代碼如下:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (list == null) {
return;
}
// Matrix mMatrix = new Matrix();
// mMatrix.postScale(0.5f,0.5f);
// mMatrix.setScale(0.5f,0.5f);//這個(gè)地方要用concat方法不能用這個(gè)方法
// canvas.concat(mMatrix);
//上面的方法也可以
// canvas.restore();
canvas.scale(scale, scale);
canvas.drawColor(Color.YELLOW);
for (int i = 0; i < list.size(); i++) {
CityPath path = list.get(i);
//繪制邊的顏色
mPaint.setStrokeWidth(2);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(Color.GRAY);
canvas.drawPath(path.getmPath(), mPaint);
}
if (mPath != null) {//mPath代表的是選中區(qū)域的path,如果不為空則一點(diǎn)擊選中區(qū)域了
mPaint.setStrokeWidth(1);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(Color.GREEN);
mPaint.setShadowLayer(8,2,2,Color.BLACK);
canvas.drawPath(mPath, mPaint);
}
mPaint.clearShadowLayer();
}
實(shí)現(xiàn)上面的方法就可以會(huì)出一個(gè)地圖了,但是沒(méi)有點(diǎn)擊事件,接下來(lái)實(shí)現(xiàn)點(diǎn)擊事件代碼如下:
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {//點(diǎn)擊的時(shí)候出發(fā)
float x = event.getX();
float y = event.getY();
if (list != null)
for (int i = 0; i < list.size(); i++) {//多所有的path進(jìn)行遍歷
CityPath cityPath = list.get(i);
if (cityPath.isArea(x / scale, y / scale)) {//這個(gè)地方要注意了,在查找點(diǎn)是否在path區(qū)域中藥除以上面的縮放比例
mPath = cityPath.getmPath();
postInvalidate();
Toast.makeText(getContext(), cityPath.getTitle(), Toast.LENGTH_SHORT).show();
break;
}
}
}
return super.onTouchEvent(event);
}
出發(fā)事件實(shí)現(xiàn)中主要的核心是判斷點(diǎn)是否在path區(qū)域內(nèi)實(shí)現(xiàn)代碼如下:
public boolean isArea(float x,float y){
RectF r=new RectF();
//計(jì)算控制點(diǎn)的邊界
mPath.computeBounds(r, true);
//設(shè)置區(qū)域路徑和剪輯描述的區(qū)域
re.setPath(mPath, new Region((int)r.left,(int)r.top,(int)r.right,(int)r.bottom));
return re.contains((int)x, (int)y);
}
上面的代碼就可以實(shí)現(xiàn)不規(guī)則區(qū)域的點(diǎn)擊了,接下來(lái)主要文件就是如何保證通過(guò)解析的svg文件可以再不同手機(jī)上的顯示適配,我這里實(shí)現(xiàn)的方法是將每個(gè)path的最小外嵌矩形的大小都統(tǒng)計(jì)出來(lái),然后進(jìn)行整合獲取所有path所在區(qū)域的最小值,然后和控件的大小進(jìn)行比較算出縮放比代碼如下:
//處理path的邊界
//計(jì)算控制點(diǎn)的邊界
mCityPath.getmPath().computeBounds(mRectF, true);
mViewAttr.colSize(mRectF);
public void colSize(RectF mRectF) {
left = left == null ? mRectF.left : Math.min(mRectF.left, left);
top = top == null ? mRectF.top : Math.min(mRectF.top, top);
right = right == null ? mRectF.right : Math.max(mRectF.right, right);
bottom = bottom == null ? mRectF.bottom : Math.max(mRectF.bottom, bottom);
}
適配完成之后就大功告成,下面是代碼的地址,如有改進(jìn)的地方歡迎提出
下載:代碼地址
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android自定義控件ListView下拉刷新的代碼
- Android自定義控件實(shí)現(xiàn)帶文字提示的SeekBar
- Android組合式自定義控件實(shí)現(xiàn)購(gòu)物車(chē)加減商品操作
- Android自定義彈窗提醒控件使用詳解
- Android自定義控件實(shí)現(xiàn)按鈕滾動(dòng)選擇效果
- Android自定義動(dòng)畫(huà)根據(jù)控件Y軸旋轉(zhuǎn)動(dòng)畫(huà)(仿紅包)
- Android自定義控件實(shí)現(xiàn)顏色選擇器
- Android自定義日歷滑動(dòng)控件
- Android自定義圖片輪播Banner控件使用解析
- Android自定義控件的步驟
相關(guān)文章
Android App中的GridView網(wǎng)格布局使用指南
GridView布局所實(shí)現(xiàn)的就是類(lèi)似于九宮格的矩陣界面效果,下面整理了Android App中的GridView網(wǎng)格布局使用指南,包括分割線(xiàn)的添加與自定義GridView的實(shí)現(xiàn)等技巧,需要的朋友可以參考下2016-06-06
android webview中使用Java調(diào)用JavaScript方法并獲取返回值
這篇文章主要介紹了android webview中使用Java調(diào)用JavaScript方法并獲取返回值,本文直接給出代碼示例,需要的朋友可以參考下2015-03-03
Android帶清除功能的輸入框控件EditTextWithDel
這篇文章主要為大家詳細(xì)介紹了Android帶清除功能的輸入框控件EditTextWithDel,感興趣的小伙伴們可以參考一下2016-09-09
Jetpack?Compose狀態(tài)專(zhuān)篇精講
在今年的Google/IO大會(huì)上,亮相了一個(gè)全新的?Android?原生?UI?開(kāi)發(fā)框架-Jetpack?Compose,?與蘋(píng)果的SwiftIUI一樣,Jetpack?Compose是一個(gè)聲明式的UI框架,這篇文章主要介紹了Jetpack?Compose狀態(tài)管理2022-10-10
Android開(kāi)發(fā)中超好用的正則表達(dá)式工具類(lèi)RegexUtil完整實(shí)例
這篇文章主要介紹了Android開(kāi)發(fā)中超好用的正則表達(dá)式工具類(lèi)RegexUtil,結(jié)合完整實(shí)例形式分析了Android正則表達(dá)式常見(jiàn)操作技巧,包括針對(duì)證件號(hào)、銀行賬號(hào)、手機(jī)號(hào)、郵編等的正則判斷相關(guān)操作技巧,需要的朋友可以參考下2017-11-11
Android數(shù)據(jù)持久化之Preferences機(jī)制詳解
這篇文章主要介紹了Android數(shù)據(jù)持久化之Preferences機(jī)制,較為詳細(xì)的分析了Android數(shù)據(jù)持久化的概念、Preferences機(jī)制的原理與相關(guān)實(shí)現(xiàn)、使用技巧,需要的朋友可以參考下2017-05-05
Android 開(kāi)發(fā)中l(wèi)ayout下的子文件夾
這篇文章主要介紹了android 開(kāi)發(fā)中l(wèi)ayout下的子文件夾,需要的朋友可以參考下2017-12-12

