安卓图像映射。 - 显示 .svg 并将其用作图像映射(触摸区)

Posted

技术标签:

【中文标题】安卓图像映射。 - 显示 .svg 并将其用作图像映射(触摸区)【英文标题】:Android image map. - displaying an .svg and using it as an image map (touch zones) 【发布时间】:2013-07-06 18:34:52 【问题描述】:

我正在寻找一种方法来显示图像并让用户点击图像的不同部分来导航和执行操作。

我正在考虑使用invisible color map 来检查哪些部分被触摸了。

但由于我也想突出显示选定的区域,所以我正在考虑使用矢量。 有一个不错的库可以将 svg 文件渲染到图像视图 here,但它不处理触摸。 那里有图书馆吗?或者有什么更聪明的方法?

(我还查看了this project,但它不会吞下 .svg 文件,而且我的矢量图太复杂,无法手动插入所有数据)

【问题讨论】:

如何在 iamge 视图之上创建一个覆盖层,它可以处理触摸,然后使用坐标突出显示图像? 如果基本上你只需要 svgs 当 webviews 出现时,你就回家了,用 danbrough 的回答干吗? 【参考方案1】:

有趣的问题!我不相信你不能使用你提到的库的组合。

我要做的是首先使用 SVG-android 以编程方式读取您的 SVG 文件。查看 SVG-Android,看起来它以 PictureDrawable 的形式返回最终产品,它是 Drawable 的子类。

在 SVG-Android 处理完 SVG 图形之后,我会使用 ImageView.setImageDrawable 来加载主 ImageView 和我们刚刚生成的 PictureDrawable。然后,我将使用 ImageView 作为您在原始问题中链接的 "Images with Clickable Areas" 实现的基础。

老实说,我认为最难的部分是让 SVG-Android 正常工作(我已经玩过它了,它有点挑剔)。但是,我认为将 SVG 生成的可绘制对象与可点击区域结合起来不会有太大困难。这是对基础图像来源的简单更改。

祝你好运!

【讨论】:

您可以分解 SVG 以创建单独的图像以显示为叠加层,并使用它们来捕捉触摸。 可能。唯一需要注意的是,可点击区域必须是矩形或间隔足够远,以便在 ImageView 中“包裹”而不重叠另一个可点击区域。如果只有图像的不透明部分是可点击的,那就太酷了;那么您绝对可以采用叠加方法。如果您编写一个小库来处理您正在触摸的像素,这可能是可行的。这实际上是一个很酷的小挑战,尽管可能不会立即实用。 不应该调用 getPixel(event.getX(),event.getY()) 并检查采样颜色的 alpha 值吗? (在 OnTochListener 中)我唯一担心的是,如果有大约 20 个触摸区域,我会创建一些严重的过度绘制......将每个图像切割成“绑定框大小”的正方形以减少过度绘制可能会起作用,但我定位所有那些具有所有不同屏幕密度的部分......头痛:) 当然。 :) 我仍然坚持我原来的答案。我只是认为替代方案将是一个有趣的小项目。 ;) @Brian 很好的解释。我有一个与从 Android 中的视图创建 SVG 格式图像有关的问题。如果您有任何想法,请告诉我...我想从我在 Android 中的数据生成 SVG 格式的图像。那么我需要做些什么呢?【参考方案2】:

不确定这是否是您所追求的,但这是一个在 Android WebView 中启用点击的 svg 示例:

WebView webView = (WebView) findViewById(R.id.webView1);
webView.getSettings().setjavascriptEnabled(true);
webView.loadUrl("http://www.w3.org/TR/SVG/images/script/script01.svg");

它应该显示一个红色圆圈,您可以单击该圆圈并且该圆圈会改变大小。

这是从资产文件夹加载的 svg 和暴露的 android javascript 接口重新处理的相同示例,因此您可以从 svg 文件回调到 android 代码。

  WebView webView;

  public class WebAppInterface 
    /** Show a toast from svg */
    @JavascriptInterface
    public void showToast(String toast) 
      Toast.makeText(MainActivity.this, toast, Toast.LENGTH_SHORT).show();
    
  

  @Override
  protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    webView = (WebView) findViewById(R.id.webView1);
    webView.getSettings().setJavaScriptEnabled(true);
    webView.addJavascriptInterface(new WebAppInterface(), "Android");

    String svg = loadSvg();
    webView.loadData(svg, "image/svg+xml", "utf-8");
  

  String loadSvg() 
    try 
      BufferedReader input = new BufferedReader(new InputStreamReader(
          getAssets().open("test.svg")));
      StringBuffer buf = new StringBuffer();
      String s = null;
      while ((s = input.readLine()) != null) 
        buf.append(s);
        buf.append('\n');
      
      input.close();
      return buf.toString();
     catch (IOException ex) 
      ex.printStackTrace();
    
    return null;
  

还有 test.svg 文件:

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 
  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg   viewBox="0 0 600 500"
     xmlns="http://www.w3.org/2000/svg" version="1.1">
  <desc>Example script01 - invoke an ECMAScript function from an onclick event
  </desc>
  <!-- ECMAScript to change the radius with each click -->
  <script type="application/ecmascript"> <![CDATA[
    function circle_click(evt) 
        Android.showToast("Hello from SVG");
      var circle = evt.target;
      var currentRadius = circle.getAttribute("r");
      if (currentRadius == 100)
        circle.setAttribute("r", currentRadius*2);
      else
        circle.setAttribute("r", currentRadius*0.5);
    
  ]]> </script>

  <!-- Outline the drawing area with a blue line -->
  <rect x="1" y="1"   fill="none" stroke="blue"/>

  <!-- Act on each click event -->
  <circle onclick="circle_click(evt)" cx="300" cy="225" r="100"
          fill="red"/>

  <text x="300" y="480" 
        font-family="Verdana" font-size="35" text-anchor="middle">
    Click on circle to change its size
  </text>
</svg>

【讨论】:

不错的创意解决方法!我猜这个骗局不得不为使用 webview 的昂贵开销付出代价。 是的,它有潜力。您也可以将 java 原语传递回 javascript。可惜你不能直接调用 javascript。 这里是一个关于基于 svg 的地图的教程,带有缩放和平移控件:petercollingridge.co.uk/interactive-svg-components/…【参考方案3】:

非常非常简单;-)

您必须创建一个 javascript 界面来处理来自 Web 视图的点击并将此文件添加到您的 Web 视图中。只需流动步骤:

1) 创建 JavaScript 接口

public class WebViewInterface 
    @JavascriptInterface
    public void showDetail(String content) 
        Toast.makeText(getActivity(), content, Toast.LENGTH_SHORT).show();
    

2) 为网页视图添加界面

WebView webView = findViewById(R.id.web_view);
webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(new WebViewInterface(), "Android");

3) 编辑与此相同的 svg 文件

<?xml version="1.0" standalone="no"?>
<svg   viewBox="0 0 600 500"
    xmlns="http://www.w3.org/2000/svg" version="1.1">
    <desc>Sample SVG</desc>
    <script type="application/ecmascript"> <![CDATA[
    function section_click(evt) 
        Android.showDetail("OnClick: " + evt.id);
    
  ]]> </script>

    <rect id="rect" onclick="section_click(this)" x="1" y="1"   fill="none" stroke="blue"/>

    <circle id="circle" onclick="section_click(this)" cx="300" cy="225" r="100"
        fill="red"/>

    <text id="text" onclick="section_click(this)" x="300" y="480"
        font-family="Verdana" font-size="35" text-anchor="middle">
        Click on each element
    </text>
</svg>

【讨论】:

以上是关于安卓图像映射。 - 显示 .svg 并将其用作图像映射(触摸区)的主要内容,如果未能解决你的问题,请参考以下文章

如何获得旋转的线性渐变 svg 用作背景图像?

如何输入图像并将其用作光标?

用作背景图像的 SVG 会丢失嵌入图像?

SVG 数据图像不能用作伪元素中的背景图像

React.js styled-components 导入图像并将其用作 div 背景

用作 base-64 背景图像数据时如何更改 svg 填充颜色?