如何将SVG源中的可缩放图标放到按钮上?

时间:2016-02-12 12:44:04

标签: android svg

我想编写类似的代码:

Context c = getContext();
Button b = new Button( c );
b.setBackground( new SvgDrawable( c.getAssets(), "iconImage.svg" ));
int pxWidth = Math.round( 48/*sp*/  // scaling to user preference
  * c.getResources().getDisplayMetrics().scaledDensity/*px per sp*/ );
addView( b, new ViewGroup.LayoutParams( pxWidth, WRAP_CONTENT ));
  // determines unspecified height from pxWidth and aspect ratio

但是没有SvgDrawable。有什么可以替代我的SVG到按钮上?

请给出适用于任何IDE的答案。我不使用Studio或Eclipse。

3 个答案:

答案 0 :(得分:1)

如果您的minSdkVersion为21或更高,正如您所说,那么您可以选择仅使用VectorDrawable。只需使用其中一个在线转换器将SVG转换为VectorDrawable。

否则,您可以使用Button并根据Surabhi的建议设置背景。

或者您可以使用ImageButton并执行

// AndroidSVG
try {
   SVG svg = SVG.getSVGFromAsset(getAssets(), "iconImage.svg");
   yourButton.setImageDrawable(new PictureDrawable(svg.renderToPicture()));
}
catch (IOException e) {
   e.printStackTrace();
}

或者如果你使用的是svg-android,那就是:

// svg-android
try {
   SVG svg = SVGParser.getSVGFromAsset(getAssets(), "iconImage.svg");
   yourButton.setImageDrawable(svg.createPictureDrawable());
}
catch (IOException e) {
   e.printStackTrace();
}

答案 1 :(得分:0)

这样做:

try {
   SVG svg = SVGParser.getSVGFromAsset(getAssets(), "iconImage.svg");
   yourButton.setBackground(svg.createPictureDrawable());
} catch (IOException e) {
   e.printStackTrace();
} 

答案 2 :(得分:0)

这是我最终确定的解决方案。

1。将SVG转换为VectorDrawable

矢量图像的首选形式通常是SVG,但Android上的本地首选项是VectorDrawable。这引发了形式问题,我选择的解决方案是变换。

以下示例源是从使用Nashorn JavaScript编写的构建脚本中提取的。

var bufferFile = tmpDir.resolve( 'vectorDrawableBuffer.xml' ); // VD out
var inX = Build.xmlInputFactory().createXMLEventReader(
  new (Java.type('java.io.BufferedInputStream'))(
    new (Java.type('java.io.FileInputStream'))( sourceFile ))); // SVG in
var out = Files.newBufferedWriter( bufferFile );
try
{
    var factory = Build.xmlEventFactory();
    while( inX.hasNext() )
    {
        var xml = inX.next();
        if( !xml.isStartElement()
         || xml.getName().getLocalPart() != 'svg' ) continue;

        var parent;
        var parents = []; // SVG
        var _parents = []; // VectorDrawable
        function indentLine()
        {
            out.newLine();
            for( var p = parents.length; p > 0; --p ) out.append( '\t' );
        }

      // svg → vector
      // - - - - - - -
        out.append(
          '<vector xmlns:a="http://schemas.android.com/apk/res/android"' );
        parents.push( parent = 'svg' );
        _parents.push( 'vector' );
        var atts;
        var att;
        var name;
        atts = xml.getAttributes();
        while( atts.hasNext() )
        {
            att = atts.next();
            name = att.getName().getLocalPart();
            if( name == 'height' )
            {
                out.append( ' a:height="' )
                  .append( att.getValue() ).append( '"' );
            }
            else if( name == 'width' )
            {
                out.append( ' a:width="' )
                  .append( att.getValue() ).append( '"' );
            }
            else if( name == 'viewBox' )
            {
              // svg[viewBox] → vector[viewportWidth, viewportHeight]
              // - - - - - - - - - - - - - - - - - - - - - - - - - - -
                var b = att.getValue().split( ' ' );
                if( /*min-x*/b[0] != '0' || /*min-y*/b[1] != '0' )
                {
                    throw "Cannot transform, viewBox displaced from origin: "
                      + sourceFile;
                }

                out.append( ' a:viewportWidth="' )
                  .append( b[2] ).append( '"' )
                  .append( ' a:viewportHeight="' )
                  .append( b[3] ).append( '"' );
            }
        }
        out.append( '>' );
        while( inX.hasNext() )
        {
            xml = inX.next();
            if( xml.isStartElement() )
            {
                if( xml.getName().getLocalPart() != 'path' ) continue;

              // path
              // - - -
                indentLine();
                out.append( '<path' );
                atts = xml.getAttributes();
                while( atts.hasNext() )
                {
                    att = atts.next();
                    name = att.getName().getLocalPart();
                    if( name == 'd' )
                    {
                      // path[d → pathData]
                      // - - - - - - - - - -
                        out.append( ' a:pathData="' )
                          .append( att.getValue() ).append( '"' );
                    }
                    else if( name == 'fill' )
                    {
                      // path[fill → fillColor]
                      // - - - - - - - - - - - -
                        out.append( ' a:fillColor="' )
                          .append( att.getValue() ).append( '"' );
                    }
                }
                out.append( '/>' );
            }
            else if( xml.isEndElement() )
            {
                name = xml.getName().getLocalPart();
                if( name == parent )
                {
                    indentLine();
                    out.append( '</' )
                      .append( _parents.pop() ).append( '>' );
                }
            }
        }
    }
}
finally
{
    out.close();
    inX.close();
}

请参阅original script file了解缺失的背景信息。

2。在按钮

上设置VectorDrawable
   final Resources res = context.getResources();
   final VectorDrawable icon;
// try
// {
//     final Class<?> c =
//       Class.forName( "android.graphics.drawable.VectorDrawable" );
//     final Method m = c.getMethod( "create", Resources.class, int.class );
//     icon = (VectorDrawable)m.invoke( null, res,
//       R.drawable.vector_drawable_res_id );
// }
// catch( final Exception ex ) { throw new RuntimeException( ex ); }
//// call to API-hidden method, but better inline it for production code:
   final XmlResourceParser p = res.getXml( R.drawable.vector_drawable_res_id );
   try
   {
       // Go to first element, else VectorDrawable throws XmlPullParserException
       // "Binary XML file line #-1<vector> tag requires viewportWidth > 0".
       for( int t = p.getEventType(); t != START_TAG; t = p.next() )
       {
           if( t == END_DOCUMENT )
           {
               throw new XmlPullParserException( "Missing start tag" );
           }
       }

       icon = new VectorDrawable();
       icon.inflate( res, p, Xml.asAttributeSet(p) );
   }
   catch( final IOException|XmlPullParserException ex )
   {
       throw new RuntimeException( ex );
   }

   button.setBackground( icon );

最后,正如所承诺的那样:

3。缩放

   final float aspectRatio =
     (float)icon.getIntrinsicWidth() / icon.getIntrinsicHeight();
   final int pxWidth = Math.round( 48/*sp*/  // scaling to user preference
     * context.getResources().getDisplayMetrics().scaledDensity/*px per sp*/ );
   final int pxHeight = Math.round( pxWidth / aspectRatio );
// icon.setBounds( /*left*/0, /*top*/0, pxWidth, pxHeight );
/// needn't scale icon itself, just the button:
   addView( button, new ViewGroup.LayoutParams( pxWidth, pxHeight ));

这不是一个查看代码的简单解决方案。但我认为它将证明前进的可靠性(更少的意外陷阱和其他隐藏的复杂性)因为它使用了双方的首选形式:源端的SVG和可执行端的VectorDrawable