衚瀺ãããç»åã¯ãã¯ãã«ã䜿çšããŠããŸãããäžå€®ã«é 眮ãããŠããŸãã ããã¯ãããïŒ ç¹å®ã®é åã§ã®ã¿ãã¯ãã«ãåŒã䌞ã°ãæ©èœã¯ãå®éã«ã¯å€§ããªæ©äŒãæäŸããŸãã ãããŠãAndroidã®ä»¥åã®ããŒãžã§ã³ã§ãã¯ã¿ãŒã䜿çšã§ããããã«ãããããžã§ã¯ãããããšèãããšããã¯ã¿ãŒç»åã¯ãã¹ãŠã®çŽ æŽããããèŠãå§ããŸãã
ãã°ãããå€æãéå§ããåã«ã詳现ãããå°ã詳ããèŠãŠãç®çã®çµæãåŸãæ¹æ³ãèŠã€ããŸãããã æåã«ãNinePatchDrawableãšã¯äœããç解ããŠã¿ãŸãããã ãŸãã2ã€ã®äž»èŠéšåã§æ§æãããŸããæåã®éšåã¯ããããããã§ã2çªç®ã¯ããã£ã³ã¯ããšåŒã°ãããã€ãã®é åã§ããã®ããããããã®ã¹ãã¬ããæ¹æ³ã«é¢ããæ å ±ãå«ãŸããŠããŸãã ãããã£ãŠãä»»æã®ãããããããšå¯Ÿå¿ããããã£ã³ã¯ãã䜿çšããŠãæšæºã¢ãã«ããã€ãã¹ããŠNinePatchDrawableãäœæã§ããŸãã9.pngãäœæãããããžã§ã¯ãã«é 眮ããŠãã³ã³ãã€ã«ããŸãã
ãã ããå®éã«ã¯ããã»ã©åçŽã§ã¯ãããŸããã äºå®ãå®éã«ã¯ãããã£ã³ã¯ããã©ã®ããã«åœ¢æããããã«é¢ããããã¥ã¡ã³ããèŠã€ããããšã¯çŸå®çã§ã¯ãããŸããã aaptãŠãŒãã£ãªãã£ã¯ãã³ã³ãã€ã«æ®µéã§ããã®çæã«é¢äžããŠãããAndroid APIã«ã¯ããã£ã³ã¯ãã®çæã«åœ¹ç«ã€ã¯ã©ã¹ã¯ãããŸããã ã¢ã¬ã€ã®å€§éšåãäœã§ããããææ¡ã§ããŸããã ççŽã«èšã£ãŠãç§ã¯ã©ã®ãã€ããäœã«è²¬ä»»ãããã®ãââãå®å šã«ã¯ç解ããŠããŸããã§ããããããã§ååã§ããããšãããããŸããã
ããã£ã³ã¯ããšã¯äœã§ããïŒ
ãã®é åããã€ãåäœã§è§£æããŸãããã ç§ãç¥ããªããã€ãã¯ããã®è¬ãšè¬ã®ããã«ãéæ³ããšåŒã¶ããšã«ããŸããã ã ããïŒ
- [0]-ãã©ã°wasDeserializedã
- [1]-XDivsé åå ã®ãã€ã³ãã®æ°ã瀺ããŸãã
- [2]-YDivsé åå ã®ãã€ã³ãã®æ°ã瀺ããŸãã
- [3]-Colorsé åã®ãã€ã³ãæ°ã瀺ããŸãã
- [4-11]-8åã®ãããžãã¯ããã€ãã
- [12-27]-ããã£ã³ã°çšã®16ãã€ãã
- [28-31]-4ã€ã®ãããžãã¯ããã€ãã
- [32-ã]-次ã¯ãXDivsãYDivsãããã³Colorsé åã®ãªã¹ãã§ãã
ãŒããã€ãã«ã¯ããŒã«å€ãwasDeserializedããæ ŒçŽãããŸãã ç§ãèŠã€ãããã¹ãŠã®äŸã§ã¯ã0x01ã§ããå¿ èŠããããŸããã代ããã«ä»ã®å€ãæå®ããŠãã²ã©ãããšã¯äœãèµ·ããããããã£ã³ã¯ãé åããã€ãã£ããªããžã§ã¯ãã«å€æãããšãã«èªåçã«trueã«èšå®ãããŸãã
ããã£ã³ã°ãXDivsãYDivsãããã³è²ã¯ãintïŒ4ãã€ãïŒã«æ ŒçŽãããŸãã ã¡ãªã¿ã«ããµã€ãã®æ°ã«å¿ããŠãããã£ã³ã°ã4ãã€ããå æããã®ã§ã¯ãªãã16ãã€ããå æããã®ã¯ãã®ããã§ãã
XDivsãšYDivsã«ã¯ãX軞ãšY軞ã«æ²¿ã£ãŠã¹ãã¬ããããé åãå«ãŸããŠããŸãã æåã®çªå·ã¯ãæåã®é åã®å§ãŸãã瀺ãããã®æ¬¡ã®é åã®ããã«ç¶ããŸãã 次ã«ã次ã®é åãåæ§ã«èª¬æããŸãã
äŸãšããŠã6 x 6ã®NinePatchç»åãèŠãŠã¿ãŸãããã
ããã§ãX軞ã«æ²¿ã£ã䌞瞮å¯èœãªé åã¯2ãã3ãã¯ã»ã«ãŸã§ãY軞ã«æ²¿ã£ãŠ2ãã4ãŸã§ã§ãããããã£ãŠãXDivsã¯[0x02ã0x00ã0x00ã0x00ã0x03ã0x00ã0x00ã0x00]ãš[ 0x02ã0x00ã0x00ã0x00ã0x04ã0x00ã0x00ã0x00]ã XDivsãšYDivsã®ãµã€ãºã決å®ããããã£ã³ã¯ãé åã®æåã®ïŒ2çªç®ã®ïŒãã€ããš2çªç®ïŒ3çªç®ã®ïŒãã€ããšããŠã0x02ãæå®ããå¿ èŠããããŸããããã¯ããããã4ãã€ãã®2ãã€ã³ããæå³ããŸãã
Colorsé åã«äœãä¿åãã¹ãããããããç解ããããã«ãåã®ç»åã«å°ããªå€æŽãå ããŸãããããäžåºŠèŠãŠã¿ãŸãããã
å³ãããããããã«ãç»åã¯9ã€ã®é åã«åå²ã§ããŸãã ãã®ãããColorsã¯ãããã®é åã®æç»æ¹æ³ã決å®ããŸãã 2ã€ã®ãªãã·ã§ã³ããããŸãã
- 0x00000000ïŒTRASPARENTïŒé åã¯éæã«ãªããŸãã
- 0x00000001ïŒNO_COLORïŒé åã衚瀺ãããŸãã
ååãæããããããããŸããããColorsã¯ç¹å®ã®è²ãæ åœããŸããããã®å Žåããã®ç®çã¯ããç°¡åã§ã-é åã®å¯èŠæ§ã瀺ãããšã§ãã
æå®ãããç»åã«ã€ããŠããã¹ãŠã®é åã衚瀺ãããŸãŸã«ããå Žåã¯ã[0x01ã0x00ã0x00ã0x00]ã9åæå®ããããã£ã³ã¯ãé åã®3ãã€ãïŒé åº4ïŒã«0x09ã«çããå€ãèšå®ããå¿ èŠããããŸãã
äžæè°ãªçºèšïŒæç»ã«é¢ä¿ãããã€ãã£ãã³ãŒãã¯äŸç¶ãšããŠColorsé åã®ãµã€ãºã§ããã圌èªèº«ãç»åã«ããã€ã®é åãããããç¥ã£ãŠãããColorsã«èšå®ãããµã€ãºã«é¢ä¿ãªãããããåãåããŸãã ãã®çµæãã¢ã¬ã€ã®å€åŽã®ã¡ã¢ãªé åã«ã¢ããŒã«ãè¡ããããã®çµæãããæç»ããå¥ã®æç»ãžãšæ¶ãããçŸãããããã»ã¯ã¿ãŒãåŸãããŸãã
æåã¯ãããã§æ¬æ ŒçãªNinePatchãäœæããã®ã«ååãã©ããçåã«æããŸããã ååã«å€æããŸããã å®éãNinePatchã¯ãããã£ã³ã¯ãã䜿çšããåã«ãvalidateNinePatchChunkã¡ãœããã䜿çšããŠãã€ãã£ãã®Res_png_9patchãªããžã§ã¯ãã«å€æããŸãã ãœãŒã¹ãèŠããšãã³ãŒããèŠããšãããã«ãããã€ãã䜿çšãããŠããªãããšãããããŸããã€ãŸãããŒããªã©ã®å€ã§åããããšãã§ããŸãã
NinePatchBuilder
ããã£ã³ã¯ããçæããæ¹æ³ãããã£ãã®ã§ãæåã«ããããããã«æç»ããå ŽåãDrawableãå«ãä»»æã®ç»åããNinePatchãäœæããããšã¯é£ãããããŸããã ãããã®æé ãç°¡çŽ åããããã«ã NinePatchBuilderã¯ã©ã¹ãäœæããããšã«ããŸããã
次ã®ã³ãŒãã¯ãéåžžã®ããããããã®å Žåã«äœ¿çšããæ¹æ³ã瀺ããŠããŸãã
NinePatchBuilder ninePatchBuilder = new NinePatchBuilder(getResources()) .addStretchSegmentX(0.49f, 0.51f) .addStretchSegmentY(0.49f, 0.51f) .setBitmap(bitmap); Drawable drawable = ninePatchBuilder.build();
addStretchSegmentã¡ãœããã¯ãã¹ãã¬ããããé åãæå®ããŸãã NinePatchãäœæãããšãã«ããµã€ãºãäºåã«ããããªãç»åã䜿çšã§ããããã[0ã1]ã®ç¯å²ã®çžå¯Ÿãµã€ãºã䜿çšããããšã«ããŸããã ãã«ããåŒã³åºããšãèšå®ããããã©ã¡ãŒã¿ãŒãšããããããã®ãµã€ãºã«å¿ããŠãããã£ã³ã¯ãã®é åã圢æãããNinePatchDrawableãäœæãããŸãã
NinePatchBuilderã®å éšã§ã¯æ¬¡ã®ããšãè¡ãããŸãã
// NinePatchBuilder. private Drawable buildFromBitmap(Bitmap bitmap) { return new NinePatchDrawable(mResources, bitmap, getChunkByteArray(bitmap), getPaddingRect(bitmap.getWidth(), bitmap.getHeight()), mSrcName); }
getChunkByteArrayã¡ãœããã³ãŒãã¯æäŸããŸããããã®å®è£ ã®å€§éšåã¯ãåè¿°ã®ããã£ã³ã¯ãçæã¢ã«ãŽãªãºã ã«åŸãããã§ãã
Drawableã«ã€ããŠãåæ§ã§ãã ããã§ã¯ãVectorDrawableãå«ããäœã§ãDrawableãšããŠæ©èœã§ããŸãã ãã®çµæããã¯ãã«ç»åã1ã€ãããªãããããã¹ãŠã®ç»é¢å¯åºŠã«å¯ŸããŠNinePatchDrawableã®å®å šãªã»ãããåŸãããŸãïŒ
ãã¯ã¿ãŒç»åããããšããŸãããã
android.xml
<?xml version="1.0" encoding="utf-8"?> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="500dp" android:height="500dp" android:viewportWidth="500" android:viewportHeight="500"> <group> <path android:fillColor="#9FBF3B" android:pathData="M301.314,83.298l20.159-29.272c1.197-1.74,0.899-4.024-0.666-5.104c-1.563-1.074-3.805-0.543-4.993,1.199 L294.863,80.53c-13.807-5.439-29.139-8.47-45.299-8.47c-16.16,0-31.496,3.028-45.302,8.47l-20.948-30.41 c-1.201-1.74-3.439-2.273-5.003-1.199c-1.564,1.077-1.861,3.362-0.664,5.104l20.166,29.272 c-32.063,14.916-54.548,43.26-57.413,76.34h218.316C355.861,126.557,333.375,98.214,301.314,83.298" /> <path android:fillColor="#FFFFFF" android:pathData="M203.956,129.438c-6.673,0-12.08-5.407-12.08-12.079c0-6.671,5.404-12.08,12.08-12.08 c6.668,0,12.073,5.407,12.073,12.08C216.03,124.03,210.624,129.438,203.956,129.438" /> <path android:fillColor="#FFFFFF" android:pathData="M295.161,129.438c-6.668,0-12.074-5.407-12.074-12.079c0-6.673,5.406-12.08,12.074-12.08 c6.675,0,12.079,5.409,12.079,12.08C307.24,124.03,301.834,129.438,295.161,129.438" /> <path android:fillColor="#9FBF3B" android:pathData="M126.383,297.598c0,13.45-10.904,24.354-24.355,24.354l0,0c-13.45,0-24.354-10.904-24.354-24.354V199.09 c0-13.45,10.904-24.354,24.354-24.354l0,0c13.451,0,24.355,10.904,24.355,24.354V297.598z" /> <path android:fillColor="#9FBF3B" android:pathData="M140.396,175.489v177.915c0,10.566,8.566,19.133,19.135,19.133h22.633v54.744 c0,13.451,10.903,24.354,24.354,24.354c13.451,0,24.355-10.903,24.355-24.354v-54.744h37.371v54.744 c0,13.451,10.902,24.354,24.354,24.354s24.354-10.903,24.354-24.354v-54.744h22.633c10.569,0,19.137-8.562,19.137-19.133V175.489 H140.396z" /> <path android:fillColor="#9FBF3B" android:pathData="M372.734,297.598c0,13.45,10.903,24.354,24.354,24.354l0,0c13.45,0,24.354-10.904,24.354-24.354V199.09 c0-13.45-10.904-24.354-24.354-24.354l0,0c-13.451,0-24.354,10.904-24.354,24.354V297.598z" /> </group> </vector>
NinePatchã«å€æããããšã¯å€§ããããšã§ã¯ãããŸããã
NinePatchBuilder ninePatchBuilder = new NinePatchBuilder(resources) .addStretchSegmentX(0.49f, 0.51f) .addStretchSegmentY(0.49f, 0.51f) .setDrawable(R.drawable.android, (int) resources.getDimension(R.dimen.android_width), (int) resources.getDimension(R.dimen.android_height));
ããã«ããã¹ãŠã®Drawableãåºå®ãµã€ãºã§ã¯ãªãããããµã€ãºããã¯ã»ã«åäœã§æå®ããå¿ èŠããããŸãã buildã®åŒã³åºãæã«ãDrawableãããããããã«æç»ããããã®ããããããã¯æ¢ã«NinePacthDrawableãäœæããããã«äœ¿çšãããŠããŸãã
ç¹å¥ãªå Žå
åœç¶ã DrawableContainerãšãã®åå«ãååšãããããæç»ãããDrawableãç²ç®çã«äœ¿çšããããšã¯å¿ ãããè¯ã解決çã§ã¯ãããŸããã ãã®ãããªè€éãªãªããžã§ã¯ãããµããŒãããã«ã¯ãç¹å®ã®ããªãã¯ãè¡ãå¿ èŠããããŸããã
// NinePatchBuilder. if (drawable instanceof DrawableContainer) { final XmlPullParser parser = mResources.getXml(drawableId); final AttributeSet attrs = Xml.asAttributeSet(parser); int type = XmlPullParser.START_DOCUMENT; try { while ((type=parser.next()) != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) { // Empty loop } } catch (XmlPullParserException | IOException e) { e.printStackTrace(); } if (type == XmlPullParser.START_TAG) { Drawable result = null; try { result = drawable.getClass().newInstance(); } catch (InstantiationException | IllegalAccessException e) { e.printStackTrace(); } if (result != null) { try { result.inflate(new ResourceWrapper(mResources), parser, attrs); return result; } catch (XmlPullParserException | IOException e) { e.printStackTrace(); } } } }
ããã¯NinePatchBuilderã®ã³ãŒãã®äžéšã§ãããClass.newInstanceïŒïŒã䜿çšããŠå ã®ã¯ã©ã¹ãšåãã¯ã©ã¹ã®æ°ããDrawableãäœæããinflateã¡ãœããã§ãããåããŸãã ããã¯ãã¹ãŠãResourceWrapperãé€ããŠãLayoutInflaterå ã§çºçãããã®ã«äŒŒãŠããŸãã ãšãã»ã³ã¹å šäœãæœãã§ããŸãã inflateã¡ãœããã®åäœãèŠããšããã©ã¡ãŒã¿ãŒãšããŠè»¢éããããªãœãŒã¹ããgetDrawableã¡ãœããã«ãã£ãŠDrawableã®åãååŸãããŠããããšãããããŸãã ç®çã®çµæãååŸããã«ã¯ããã®ã¡ãœããããªãŒããŒã©ã€ãããŸãã
// NinePatchBuilder. private class ResourceWrapper extends Resources { public ResourceWrapper(Resources resources) { super(resources.getAssets(), resources.getDisplayMetrics(), resources.getConfiguration()); } @Override public Drawable getDrawable(int id) throws NotFoundException { return buildFromDrawable(id, mDrawableWidth, mDrawableHeight); } @Override public Drawable getDrawable(int id, Theme theme) throws NotFoundException { return buildFromDrawable(id, mDrawableWidth, mDrawableHeight); } }
ãã®ãè³ã®ãã§ã€ã³ããã®ãããã§ãããããã¬ãã«ã®ãã¹ããæã€ãã¹ãŠã®DrawableContaineråå«ã®å®å šãªãµããŒããå®è£ ããStateListDrawableãå€æãããšãåºåã¯NinePatchDrawableã§æ§æãããStateListDrawableã«ãªããŸãã
XMLãšãã£ãã·ã³ã°
ãããã«ããŒã§ã¯ååã§ã¯ãªãã£ããããXMLãã¡ã€ã«ããNinePatchãåéããNinePatchInflaterã¯ã©ã¹ãäœæããããšã«ããŸãã ã ãã®çµæãDrawableã¯æ¬¡ã®ããã«èšè¿°ã§ããŸãã
<nine-patch-plus xmlns:auto="http://schemas.android.com/apk/res-auto" auto:src="@drawable/android" auto:width="@dimen/android_width" auto:height="@dimen/android_height" auto:stretchX="0.49, 0.51" auto:stretchY="0.49, 0.51" />
ãã¡ã€ã«ã¯ãxmlããã©ã«ããŒã«ããå¿ èŠããããŸãã çŸåšããã®ãããªDrawableã®äœæã«é¢ä¿ããã³ãŒãã¯1è¡ã«åæžã§ããŸãã
Drawable drawable = NinePatchInflater.inflate(resources, R.xml.vector_drawable_nine_patch);
ã»ãšãã©ã®ã³ãŒããå¥ã®ãã¡ã€ã«ã«é 眮ããããšã«å ããŠãinflater-aã«ã¯å¥ã®å€§ããªå©ç¹ããããŸã-ãªãœãŒã¹IDã«ãããã£ãã·ã¥ã§ãã å®éãDrawableã®äœæã¯éåžžã«è²»çšã®ãããæäœã«ãªãå¯èœæ§ããããŸããç¹ã«ç§ãã¡ã®å Žåã1ã€ã®DrawableãååŸããå Žåãå°æ¥å¿ èŠã®ãªããªããžã§ã¯ãã®æãäœæããå¿ èŠããããŸãã ãããããå¿ èŠãªäœæ¥ã®ã»ãšãã©ã¯æ¢ã«ConstantStateã¯ã©ã¹ã§è¡ãããŠããããããã£ãã·ã¥ã§äœæãããDrawableã®ConstantStateãä¿åããå¿ èŠã«å¿ããŠConstantState.newDrawableïŒïŒã¡ãœããã䜿çšããŠæ°ããDrawableãäœæããã ãã§ãã 詳现ã¯èª¬æããŸããããèšäºã¯åºç¯å²ã«ãããããšãå€æããŸãããããã«ãç§ã¯æ°ããããšãæãã€ããŸããã§ãããããããªãœãŒã¹ã¯ã©ã¹ã§ãã£ãã·ã¥ãçºçããæ¹æ³ã§ãã
ãããã«
ãã ãããªãœãŒã¹ã®å®å šãªã©ãããŒãäœæããŠãããã°ã©ã ã³ãŒããèšè¿°ããã«XMLããŒã¯ã¢ããã«ãããã®ãã¡ã€ã«ãžã®ãªã³ã¯ãçŽæ¥æ¿å ¥ã§ããããã«ããããšã¯æªããããŸããã§ããããããŸããããŸããã§ããã å€æããããã«ããã¥ãŒãäœæãããšããå Žæã§ã¯ãããã©ã«ãã®ã¢ã¯ã»ã¹ä¿®é£Ÿåãæã€ã¡ãœããã䜿çšãããDrawableã¯ã©ã¹ã®éçã¡ãœãããçŽæ¥åŒã³åºãããããšããããŸãã ããã«ãããããããç§ã¯ãå®å šãªç¯å²ã§ã¯ãªãããæãŸããçµæãéæããããšä¿¡ããŠããŸãã
GitHubãããžã§ã¯ãïŒ NinePatchBuildUtils
ãããžã§ã¯ããžã®æ¥ç¶æ¹æ³
2ã€ã®ãªãã·ã§ã³ããããŸãã
1ãªãã·ã§ã³ïŒé¡ïŒïŒ
2ãªãã·ã§ã³ïŒãšã¬ã¬ã³ãïŒïŒ
1ãªãã·ã§ã³ïŒé¡ïŒïŒ
- ninepatchbuildutilsã¢ãžã¥ãŒã«ãå«ããã©ã«ããŒããããžã§ã¯ãã«ã³ããŒããŸã
- settings.gradleãã¡ã€ã«ã«ä»¥äžãè¿œå ããŸãã
include ':ninepatchbuildutils'
- ã¢ããªã±ãŒã·ã§ã³ã¢ãžã¥ãŒã«ã®build.gradleãã¡ã€ã«ã«äŸåé¢ä¿ãè¿œå ããŸãã
compile project(':ninepatchbuildutils')
- ãããžã§ã¯ãããªãã«ããã
2ãªãã·ã§ã³ïŒãšã¬ã¬ã³ãïŒïŒ
- ãããžã§ã¯ããgitaããå¥ã®ãã©ã«ããŒïŒãNinePatchBuildUtilsããªã©ïŒã«ããŠã³ããŒãããŸãã
- settings.gradleãã¡ã€ã«ã«ä»¥äžãè¿œå ããŸãã
include ':ninepatchbuildutils' project(':ninepatchbuildutils').projectDir = new File('< >/NinePatchBuildUtils/ninepatchbuildutils/')
project(':ninepatchbuildutils').projectDir = new File(settingsDir, '../NinePatchBuildUtils/ninepatchbuildutils/')
- ã¢ããªã±ãŒã·ã§ã³ã¢ãžã¥ãŒã«ã®build.gradleãã¡ã€ã«ã«äŸåé¢ä¿ãè¿œå ããŸãã
compile project(':ninepatchbuildutils')
- ãããžã§ã¯ãããªãã«ããã
NinePatchãœãŒã¹ïŒ NinePatch.javaããã³NinePatch.cpp
Res_png_9patchã«ã€ããŠèªãããšãã§ããå ŽæïŒ ResourceTypes.hããã³ResourceTypes.cpp
ãæž èŽããããšãããããŸããïŒ