ãšã³ããªãŒ
ãæšæ¶ãååïŒ
å€ãã®å Žåããã«ãã¡ãã£ã¢Androidã¢ããªã±ãŒã·ã§ã³ïŒä»¥äžãåã«ãã¢ããªã±ãŒã·ã§ã³ãïŒãéçºãããšããã·ã¹ãã ã§æäŸãããŠããªãç¬èªã®ã³ã³ããŒãã³ããäœæããã¿ã¹ã¯ã«çŽé¢ããŸãã ããããçš®é¡ã®ã¹ã€ãããããã¹ãã¯ãã«ããžã¥ã¢ã©ã€ã¶ãŒãªã©ã䜿çšã§ããŸãããããã®äžéšã¯ãåã«ã°ã©ãã£ãã¯ãªãœãŒã¹ã亀æãããããã£ã³ãã¹ã90床å転ããããããããšã§ååŸã§ããŸãããããããŒããã
ãã®èšäºã§ã¯ãViewã¯ã©ã¹ããã®ç¶æ¿ã䜿çšãããã¹ãŠã®å éšããç¬ç«ããŠãå®è£ ããã·ã³ãã«ãªãã¢ãããŒããŒãã§ããã³ã³ããŒãã³ãã®äœæã«ã€ããŠèª¬æããŸãã åŒçšç¬Šã§å²ãçç±-詳现ãåç §ããŠãã ããã
äžé£ã®èšäºã§ã¯ã次ã®ãããªåé¡ã匷調ããŸãã
- ã³ã³ããŒãã³ãã¬ã³ããªã³ã°
- æšæºã®ã¹ã¯ããŒã«ããŒã䜿çšããŠã¹ã¯ããŒã«ãè¿œå ãã
- ããŒã®ã»ã¬ã¯ã¿ãŒã䜿çšããçžäºäœçš
- ç»é¢ãå転ããããšãã«ã³ã³ããŒãã³ãã®ç¶æ ãä¿åãã
- ãªãŒããŒã¹ã¯ããŒã«ã®ããã¯ã©ã€ããè¿œå ãã
- ãã©ã¡ãŒã¿ãXMLã«æž¡ã
- ãã³ããºãŒã
æåã®èšäºã¯ãæåã®3ã€ã®ãã€ã³ãã«ã€ããŠã§ãã
ãããã®ãããã¯ã«èå³ãããå Žåã¯ãcatã«ããããã
èæ¯
ããããããã以åã®èšäºã§è©±ããé³æ¥œã¢ããªãæžãããšãããã¢ããåãå¿ èŠã«çŽé¢ããŸããã ããã¯ç§ã®æåã®Androidã¢ããªã±ãŒã·ã§ã³ã§ãããAndroidã¯çŸåšãšãŸã£ããåãã§ã¯ãªãã£ãã®ã§ãæåã®ããŒãžã§ã³ã§ã¯ãå€ããå°ãªããæ©èœããã³ã³ããŒãã³ããäœæããããã«1ã€ä»¥äžã®ããŒãžã§ã³ãäœæããŸããã ã¹ã¯ããŒã«ã®ããã«ãç¹å®ã®ééã§ã¹ã¯ããŒã«ã®é床ãåšæçã«äœäžããã次ã®ã¿ã¹ã¯ãåä¿¡ããããŸã§ç ã蟌ãã å¥ã®ã¹ããªãŒã ããããŸããã 察話æ§ã¯ãŒãã§ããã
ä»ããã°ããããŠãç§ã¯æåã®ãããžã§ã¯ãã«äŒŒãå€ãã®æ¹æ³ã§ãããžã§ã¯ããæžããŠããŸãããå質ãšæ©èœããŸã£ããç°ãªãã¬ãã«ã§ãããåã³ãã¢ããå¿ èŠã§ãã ãããç§ã話ãããšã§ãã
ã³ã³ããŒãã³ãéçº
ãã¥ãŒãŸãã¯SurfaceViewïŒ
ç§ãèªåã®ããã«åºããçµéšåã¯ãã§ããã ãè€éãªã°ã©ãã£ãã¯ã¹ïŒã²ãŒã ããããªïŒã§ããçš®ã®å€åããç¶æ ãåžžã«æç»ããã³ã³ããŒãã³ããå¿ èŠã§ãªãéããå¯èœãªéãViewã䜿çšããSurfaceViewãé¿ããããšã§ãã ãã®ä»ã®å Žåã¯ãã¹ãŠããã¥ãŒãéžæãããŸãã ãŸããSurfaceViewã䜿çšãããšãã¬ã€ã¢ãŠãã§ãã®ã³ã³ããŒãã³ããã¢ãã¡ãŒã·ã§ã³åããæ©èœã倱ãããããšãèæ ®ããå¿ èŠããããŸãã
åæ段é
ããã§ã¯ãå§ããŸããããæåã«è¡ãããšã¯ãandroid.view.Viewã®ç¶æ¿è ã§ããæ°ããã¯ã©ã¹ãäœæããããšã§ãã PianoViewãšåŒã³ãŸãããã
public class PianoView extends View { public PianoView(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); } }
ã芧ã®ãšãããã³ã³ããã¹ããšäžé£ã®å±æ§ãæž¡ãããã³ã³ã¹ãã©ã¯ã¿ãŒããããŸãã onDrawã¡ãœããã§ãã³ã³ããŒãã³ããæç»ããŸãã ãã®ã¡ãœããã¯ãããšãã°ã¢ãã¡ãŒã·ã§ã³ã®ãã¬ãŒã ããšã«ãã¥ãŒãåæç»ããå¿ èŠãçãããã³ã«åŒã³åºãããŸãã
ããŒããŒãã¬ã³ããªã³ã°ã ã°ã©ãã£ãã¯ãªãœãŒã¹ã
ããŒãæç»ããã«ã¯ãæšæºã®AndroidããŒã«ã䜿çšããŸãïŒã»ã¬ã¯ã¿ãŒã9ãããæç»å¯èœã
çœéµã«ã€ããŠã¯ã次ã®9ãããã€ã¡ãŒãžãçšæããŸããã Holoã®æšæºã®éãããã¯ã©ã€ãã䜿çšããŠã匷調衚瀺ç¶æ ã«ããããšã«ããŸããã
é»ã®å ŽåïŒ
ãããŠãããããã«å¯ŸããŠã»ã¬ã¯ã¿ãŒãäœæããŸããïŒ
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/white_key_pressed" android:state_pressed="true"></item> <item android:drawable="@drawable/white_key"></item> </selector>
ããšã¯ã
context.getResourses.getDrawable();
ã䜿çšããŠã³ãŒãå ã§ãããã®DrawableãååŸããã ã
context.getResourses.getDrawable();
ããŒããŒãã¬ã³ããªã³ã°ã ã³ãŒã
ãã®ãããã³ã³ããŒãã³ãã³ãŒãããããã«ä¿ã€ããã«ããã¹ãŠã®ããŒããŒãã¬ã³ããªã³ã°ãåé€ããããã«å¿ èŠãªæ å ±ãKeyboardã¯ã©ã¹ã«ä¿åããŸããã
onDraw
ãã®ã¡ãœãããåŒã³åºãã ãã§ãã
protected void onDraw(Canvas canvas) { if (measurementChanged) { measurementChanged = false; keyboard.initializeInstrument(getMeasuredHeight(), getContext()); instrumentWidth = keyboard.getWidth(); } keyboard.draw(canvas); }
ãã¢ããã©ã®ããã«ã¬ã³ããªã³ã°ããããã«ã€ããŠã¯ãéå±ãªããã¹ããšã³ãŒãã§ã¹ããŒã¹ãåããããŠããããã詳现ã«èª¬æããŸããã 詳现ãæ€èšããã人ã¯èª°ã§ãç§ã®ã³ãŒããåãåã£ãŠèŠãããšãã§ããŸãã ããã§ã¯ãåçã®ã¿ã説æããŸãã
æåã®ã¹ãããã¯åæåã§ãã åæåã«ã¯ãããŒã®é åã®èšç®ãå«ãŸããŸãã
Key[] keysArray;
ãããç§ãã¡ã®ã¢ãã«ã§ãã åã¢ã€ãã ã¯ããŒã§ãã ããŒã¯ããã®åº§æšïŒã³ã³ããŒãã³ã座æšç³»ïŒãšå¯žæ³ãé»ãçœãããŸãã¯çŸåšæŒãããŠãããã©ãããç¥ã£ãŠããŸãã
class Key { float startX; float endX; float startY; float endY; int midiCode; boolean black; boolean pressed = false; void setBounds(float startX, float endX, float startY, float endY) { this.startX = startX; this.startY = startY; this.endX = endX; this.endY = endY; } boolean containsPoint(float x, float y) { return startX <= x && endX > x && startY <= y && endY > y; } }
ãã®ããã»ã¹ã¯ãã³ã³ããŒãã³ãã®ç©çãµã€ãºãå€æŽããããã³ã«çºçããããŒããŒããåæåãããŸãïŒonMeasureã¡ãœããã§åçŽã«trueã«èšå®ãããã®ã¯ãmeasurementChangedãã©ã°ã®åœ¹å²ã§ãïŒã ãããã£ãŠãæç»ãããã³ã«ããŒã®äœçœ®ãèšç®ããŸããã
åæåã³ãŒã
public void initializeInstrument(float measuredHeight, Context context) { whiteKeyWidth = Math.round(measuredHeight / WHITE_KEY_ASPECT_RATIO); octaveWidth = whiteKeyWidth * 7; int blackHalfWidth = octaveWidth / 20; blackKeyHeight = Math.round(measuredHeight / BLACK_KEY_HEIGHT_PERCENT); keysArray = new Key[KEYS_IN_OCTAVE * OCTAVES]; int whiteIndex = 0; int blackIndex = 0; for (int i = 0; i < KEYS_IN_OCTAVE; i++) { Key key = new Key(); if (isWhite(i)) { key.black = false; key.setBounds(whiteKeyWidth * whiteIndex, whiteKeyWidth * whiteIndex + whiteKeyWidth, 0, measuredHeight); whiteIndex++; } else { key.black = true; int indexDisplacement = i == 1 || i == 3 ? 1 : 2; key.setBounds(whiteKeyWidth * (blackIndex + indexDisplacement) - blackHalfWidth, whiteKeyWidth * (blackIndex + indexDisplacement) + blackHalfWidth, 0, blackKeyHeight); blackIndex++; } key.midiCode = START_MIDI_CODE + i; keysArray[i] = key; } for (int i = KEYS_IN_OCTAVE; i < KEYS_IN_OCTAVE * OCTAVES; i++) { Key firstOctaveKey = keysArray[i % KEYS_IN_OCTAVE]; Key key = firstOctaveKey.clone(); key.startX += (i / KEYS_IN_OCTAVE) * octaveWidth; key.endX += (i / KEYS_IN_OCTAVE) * octaveWidth; key.midiCode = START_MIDI_CODE + i; keysArray[i] = key; } }
ããã§ã¯ãã³ã³ããŒãã³ãã®é«ãã«åºã¥ããŠããŒã®å¹ ãèšç®ããããŒã®é åãäœæããŸãã æåã«ãæåã®ãªã¯ã¿ãŒããæ§ç¯ããã次ã«ãæ®ãã®ãªã¯ã¿ãŒããååŸããããã«å¿ èŠãªåæ°ã ãè€è£œãããX軞ã«æ²¿ã£ãŠã·ãããããŸãã ãŸããåããŒã«ã¯MIDIã³ãŒãããããããã«å¿ããŠãµãŠã³ããåçã§ããŸãã Midiã³ãŒãã«ã¯ããšã³ãããŒãšã³ãã®çªå·ä»ãããããŸãã æåã®ããŒã³ãŒãã¯START_MIDI_CODEã§ãã ããŒã®ã³ãŒãã¯ãé åå ã®ããŒã®éå§ã³ãŒããšã€ã³ããã¯ã¹ãè¿œå ããããšã§èšç®ãããŸãã
次ã¯ãããŒã®ã¬ã³ããªã³ã°ã§ãã ããŒã®é åå šäœã®ã«ãŒãã§ã¯ã次ã®ããã«æç»ããŸãã
private void drawSingleKey(Canvas canvas, Key key, int firstVisibleKey, int lastVisibleKey) { Drawable drawable = key.black ? blackKeyDrawable : whiteKeyDrawable; drawable.setState(new int[] { key.pressed ? android.R.attr.state_pressed : -android.R.attr.state_pressed }); drawable.setBounds((int) key.startX, (int) key.startY, (int) key.endX, (int) key.endY); drawable.draw(canvas); }
ã¬ã³ããªã³ã°ã¯2段éã§è¡ãããŸããæåã«çœãããŒãæç»ãã次ã«ãªãŒããŒã¬ã€ããªãããã«é»ãæç»ããå¿ èŠãããããã§ãã 9ããŒããããé·æ¹åœ¢ã§ã¯ãªããåãæãã§äœæãããŠããå Žåããããåé¿ã§ããŸãã ããã«ãããã¯äœåãªåæç»ããããã¯ã»ã«ãåé€ããã®ã«åœ¹ç«ã¡ãŸããããã®èšäºã®ç®çã®ããã«ããã¹ãŠãã§ããã ãããªããã£ãã«ä¿ã¡ãŸãããã
å®äºãããŒã«ã¯æ£åžžã«æç»ãããŸããïŒ
æªããªãã ãã¡ãããããŒãã¯ãªãã¯ããŠãäœãèµ·ãããŸããã ãããä¿®æ£ããŸãããã
äž»èŠãªçžäºäœçš
ãŠãŒã¶ãŒã®ã¯ãªãã¯ãšã®çžäºäœçšã§ã¯ãéåžžonTouchEventã¡ãœãããåå®çŸ©ããããŠãŒã¶ãŒãäœããããã決å®ããŸã-æã®ã¿ããããžã§ã¹ãã£ã®å®è¡ãããã«ã¿ããããã³ã°ã¿ãããªã©ã
ãã©ãããã©ãŒã ããæåã«æäŸãããGestureDetectorã¯ã©ã¹ã䜿çšããŸãã
ããŒã«ã«
private GestureDetector gestureDetector;
ãã£ãŒã«ããè¿œå ããŸããã
private GestureDetector gestureDetector;
ãããŠãããåæåãã
private void init() { if (!isInEditMode()) { gestureDetector = new GestureDetector(getContext(), gestureListener); } }
ãªã¹ããŒGestureListenerãã³ã³ã¹ãã©ã¯ã¿ãŒã«æž¡ããŸããããã¯ããžã§ã¹ãã£ãŒãæ€åºããããšãã«æ€åºåšããã³ãŒã«ããã¯ãååŸããå Žæã§ãã
private OnGestureListener gestureListener = new GestureDetector.SimpleOnGestureListener() { public boolean onDown(MotionEvent e) { if (keyboard.touchItem(e.getX(), e.getY())) { invalidate(); } return true; } public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { resetTouchFeedback(); return true; } public boolean onSingleTapUp(MotionEvent e) { resetTouchFeedback(); return super.onSingleTapUp(e); } };
ãã®ãããæäœã¢ã«ãŽãªãºã ã¯åçŽã§ã.onDownã¡ãœããã§ã¯ãããŒã¹ãããŒã¯ã®åº§æšãããŒããŒãã«æž¡ããããã§æŒãããããŒãæ€çŽ¢ããŸãïŒtouchItemã¡ãœããã¯ãé åå šäœãã¹ãã£ã³ããããšãªããããŒã®åº§æšã«ãã£ãŠã€ã³ããã¯ã¹ãèšç®ããŸãïŒã ããŒãèŠã€ãã£ãå Žåããã®ããŒã¯æŒããããã®ãšããŠããŒã¯ãããç¡å¹åãšåŒã°ããåæç»ã«ã€ãªãããŸãã
ä»ã®æ¹æ³ã§ã¯ãæŒãããããŒããªã»ããããŸãïŒã¹ã¯ããŒã«ãæãé¢ãããšããªã©ïŒã ããã¯ãããšãã°ListViewã®å Žåãšåæ§ã«è¡ãããŸããã·ãŒãã®ã¹ã¯ããŒã«ãéå§ãããšãéžæããªã»ãããããŸãã
次ã®ã¹ãããã¯ãæ€åºåšãã³ã³ããŒãã³ãã«æ¥ç¶ããããšã§ãã ããã¯éåžžã«ç°¡åã«è¡ãããŸãïŒ
public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); if (action == MotionEvent.ACTION_CANCEL) { resetTouchFeedback(); } return super.onTouchEvent(event) || gestureDetector.onTouchEvent(event); }
ãŸããã¢ã¯ã·ã§ã³ã
ACTION_CANCEL
ã§ãããã©ã
ACTION_CANCEL
確èªããŸãããã®å Žåãéžæããªã»ããããŸããããã¯ãGestureDetectorãäœããã®æ¹æ³ã§ããã«åå¿ããªãããã§ããçªç¶çºçããå Žåãæ°žä¹ ã«éžæãããããŒãæ®ãå¯èœæ§ããããŸã
ç§ãã¡ã¯ãã§ãã¯ããŸãïŒ
ãããä»ã¯ããå°ãçããŠããããã ã ãããããŸã ããŒããŒãã®äžéšãã衚瀺ãããŠããŸãã...åé¡ã§ã¯ãããŸãããã¹ã¯ããŒã«ãæ¢ããŸãããã
ã³ã³ããŒãã³ããžã®ã¹ã¯ããŒã«ã®è¿œå
ããã§ã¯ããŸããã³ã³ãã³ããã©ã®ããã«ã·ããããããèããŠã¿ãŸãããã æãç°¡åãªæ¹æ³ã¯ãäœãã·ãããããåãæ¹æ³ã§æç»ããããšã§ããããã£ã³ãã¹èªäœã移åããããšã§ãã Canvasã¯ã©ã¹ã䜿çšãããšãèªåã§ã¢ãã£ã³å€æãå®è¡ã§ããŸãã
ã·ã³ãã«ãªãã£ãŒã«ããè¿œå ããŸããã
private int xOffset;
ã¯ã©ã¹ã«ã
次ã®ãããªæ§é ã§onDrawã¡ãœãããæ¡åŒµããŸãã
protected void onDraw(Canvas canvas) { if (measurementChanged) { measurementChanged = false; keyboard.initializeInstrument(getMeasuredHeight(), getContext()); instrumentWidth = keyboard.getWidth(); } canvas.save(); canvas.translate(-xOffset, 0); keyboard.updateBounds(xOffset, canvasWidth + xOffset); keyboard.draw(canvas); canvas.restore(); }
ç§ãã¡ããã£ãããšãèŠãŠã¿ãŸãããïŒ
- canvas.saveïŒïŒ-ãã£ã³ãã¹ã®çŸåšã®ç¶æ ãèšæ¶ããŸãã äžçš®ã®ãã¬ãŒã¯ãã€ã³ããäœæããŸã
- canvas.translateïŒïŒ-ãã£ã³ãã¹ãæå®ãããè·é¢ã ãã·ããããŸã
- canvas.restoreïŒïŒ-ãã£ã³ãã¹ãå ã®ç¶æ ã«åŸ©å ããŸãã
ãŸããããŒããŒãã¯ã©ã¹ã«updateBoundsã¡ãœãããè¿œå ããŸããã ããã«ãããç»é¢ãè¶ ããŠããŒãæç»ãããªãããã«ãå·Šå³ã®è¡šç€ºå¢çç·ãæž¡ãããšãã§ããŸãã ãã®ãããªæé©åã
æç»æ®µéã§ã®ã¹ã¯ããŒã«ã®ãµããŒããè¿œå ããã®ã§ããŠãŒã¶ãŒã€ã³ã¿ã©ã¯ã·ã§ã³-GestureDetectorã«ã¹ã¯ããŒã«ãè¿œå ããŸãã onScrollã®å€æŽïŒ
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { resetTouchFeedback(); xOffset += distanceX; if (xOffset < 0) { xOffset = 0; } if (xOffset > instrumentWidth - getMeasuredWidth()) { xOffset = instrumentWidth - getMeasuredWidth(); } invalidate(); return true; }
å®äºããŸãããä»ãããŒããŒãäžã§æãåãããšãããŒããŒããé¢ããããšãªããã¥ãŒãã«ã¹ã¯ããŒã«ããŸãã ããããããã ãã§ã¯ååã§ã¯ãããŸããã æãåŒã£åŒµããããŒããŒãã®æ £æ§ãèµ·åã§ããããã«ããã-æããã
幞ããªããšã«ãç»é¢äžã§æã®é床ãšæã移åããè·é¢ãèšç®ããå¿ èŠã¯ãããŸããã ãããã¯ãã¹ãŠãææã®GestureDetectorã«ãã£ãŠè¡ãããŸãã onFlingã¡ãœããããªãŒããŒã©ã€ãããã ãã§ãã 圌ã¯ããŠãŒã¶ãŒãéããŠããããšãšã圌ã®æåã®ç¹æ§ãèŠã€ããã®ã«åœ¹ç«ã¡ãŸãã ããããã¹ã¯ããŒã«ã®ç¶æ ã远跡ããéå§ãã€ã³ããšãã¡ãããã€ã³ãã®éãè£éããã«ã¯ãå¥ã®ã³ã³ããŒãã³ã-ScrollerããŸãã¯ãã®å åŒ-OverScrollerïŒä»åŸã°ããŒå¹æãè¿œå ãããïŒãå¿ èŠã§ãã Scrollerã¯ãAndroidã®ããããã¿ã€ãã®ã¹ã¯ããŒã«ã«éåžžã«åœ¹ç«ã€ã³ã³ããŒãã³ãã§ãããç¡æ°ã®å éšã³ã³ããŒãã³ãã§äœ¿çšãããæšæºã®ã¹ã¯ããŒã«åäœãå®è£ ããŠããŸãã
ã¹ã¯ããŒã©ãŒãè¿œå ããŸãã
private OverScroller scroller;
ã³ã³ããŒãã³ãã³ã³ã¹ãã©ã¯ã¿ãŒã§åæåããŸãã
次ã«ãGestureDetectorã次ã®ããã«å€æŽããŸãã
private OnGestureListener gestureListener = new GestureDetector.SimpleOnGestureListener() { public boolean onDown(MotionEvent e) { scroller.forceFinished(true); if (keyboard.touchItem(e.getX() / scaleX + xOffset, e.getY())) { invalidate(); } return true; } public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { scroller.fling(xOffset, 0, (int) -velocityX, 0, 0, instrumentWidth - getMeasuredWidth(), 0, 0); return true; } // ... };
ã³ãŒããããããããã«ãæåã®ãªãã»ãããšé床ã§ã¹ã¯ããŒã©ãŒãèµ·åããã¹ã¯ããŒã«ã®æå°ãšæ倧ã瀺ããŸãã
次ã®ã¹ãããã¯onDrawã§ã
protected void onDraw(Canvas canvas) { if (scroller.computeScrollOffset()) { xOffset = scroller.getCurrX(); } if (measurementChanged) { measurementChanged = false; keyboard.initializeInstrument(getMeasuredHeight(), getContext()); instrumentWidth = keyboard.getWidth(); } canvas.save(); canvas.scale(scaleX, 1.0f); canvas.translate(xOffset , 0); keyboard.updateBounds(xOffset , canvasWidth + xOffset ); keyboard.draw(canvas); canvas.restore(); if (!scroller.isFinished()) { ViewCompat.postInvalidateOnAnimation(this); } }
ããã§äœãå€ãã£ãã®ã§ããïŒ scroller.computeScrollOffsetïŒïŒãåŒã³åºãã¢ãã¡ãŒã·ã§ã³ã®åãã¬ãŒã ã§ããã®ã¡ãœããã¯ãã¹ã¯ããŒã©ãŒãã¢ãã¡ãŒã·ã§ã³åãããŠããå Žåã«trueãè¿ããxOffsetå€æ°ã®çŸåšã®å€ãååŸããŸãã
ã¢ãã¡ãŒã·ã§ã³ã«ã¯äžé£ã®åæç»ãå«ãŸãããããã¡ãœããã®æåŸã§ãã¹ã¯ããŒã©ãŒã®ã¢ãã¡ãŒã·ã§ã³åãå®äºããŠãããã©ããã確èªããå®äºããŠããªãå Žåã¯ãã¢ãã¡ãŒã·ã§ã³ã®æ¬¡ã®ãã¬ãŒã ãå²ãåœãŠãŸãã ãããã£ãŠãã¹ã¯ããŒã©ãŒãäœæ¥ãå®äºãããã匷å¶çã«åæ¢ããããŸã§ãonDrawã¡ãœãããå¯èœãªéãé »ç¹ã«åŒã³åºãããã³ã³ããŒãã³ããæç»ããŸãã
ããã§ãã³ã³ããŒãã³ãã¯ããŸãã¹ã¯ããŒã«ããããªã³ã°ããµããŒãããŸãã ããããäœãäžè¶³ããŠããŸãããïŒ ä»¥äžã®æšæºã¹ã¯ããŒã«ããŒãååã§ã¯ãããŸããã åé¡ãããŸããã
æšæºã®ã³ãŒã«ããŒãè¿œå ãã
æšæºã®ã¹ã¯ããŒã«ããŒãè¿œå ããããšã¯åªæã®ãããªãã®ã§ãç¹å¥ãªç§å¯ã¯ãªããäžé£ã®ã¢ã¯ã·ã§ã³ããããŸãã
æåã«ããã¹ãŠã®æšæºã®ã¹ã¯ããŒã«å±æ§ããµããŒãããããšãã³ã³ããŒãã³ãã«äŒããå¿ èŠããããŸãã ãããè¡ãã«ã¯ãvaluesãã£ã¬ã¯ããªã«attrs.xmlãã¡ã€ã«ãäœæãã次ã®å®çŸ©ãè¿œå ããŸãã
<declare-styleable name="View"> <attr name="android:fadeScrollbars" /> <attr name="android:scrollbarAlwaysDrawHorizontalTrack" /> <attr name="android:scrollbarAlwaysDrawVerticalTrack" /> <attr name="android:scrollbarDefaultDelayBeforeFade" /> <attr name="android:scrollbarFadeDuration" /> <attr name="android:scrollbarSize" /> <attr name="android:scrollbarStyle" /> <attr name="android:scrollbarThumbHorizontal" /> <attr name="android:scrollbarThumbVertical" /> <attr name="android:scrollbarTrackHorizontal" /> <attr name="android:scrollbarTrackVertical" /> <attr name="android:scrollbars" /> </declare-styleable>
次ã«ãã³ã³ã¹ãã©ã¯ã¿ã«è¿œå ããŸãã
setVerticalScrollBarEnabled(false); setHorizontalScrollBarEnabled(true); TypedArray a = context.obtainStyledAttributes(R.styleable.View); initializeScrollbars(a); a.recycle();
次ã®ã¹ãããã¯ãã¹ã¯ããŒã«ããŒã®ãµã€ãºãšäœçœ®ãå¶åŸ¡ãã3ã€ã®æãç°¡åãªæ¹æ³ãåå®çŸ©ããããšã§ãã
protected int computeHorizontalScrollExtent() { return canvasWidth; } @Override protected int computeHorizontalScrollOffset() { return xOffset; } @Override protected int computeHorizontalScrollRange() { return instrumentWidth; }
ã³ãŒãã¯ããèªäœãç©èªã£ãŠããŸã-æåã®æ¹æ³ã§ã¯ã³ã³ããŒãã³ãã®å¹ ãæå®ãã2çªç®ã§ã¯ã¹ã¯ããŒã«ã®çŸåšã®ãªãã»ãããæå®ãã3çªç®ã§ã¯ããŒããŒãå šäœã®ãµã€ãºãæå®ããŸãïŒç»é¢ãè¶ ããŸãïŒã ããã§ãå¿ èŠãªãšãã«ãããã®ã¹ã¯ããŒã«ããŒããèµ·åãããããšãã§ããŸãã åºæ¬Viewã¯ã©ã¹ã¯ããã®ããã®ç¹å¥ãªawakenScrollBarsïŒïŒã¡ãœãããæäŸããŸãã 次ã®è¡ãè¿œå ããŸãã
if (!awakenScrollBars()) { invalidate(); }
GestureDetectorListenerã®onScrollããã³onFlingã¡ãœãããžã
çµæ-æšæºã®ã¹ã¯ããŒã«ããŒã¯ç§ãã¡ã®ç®ã楜ããŸããŸãã
ãããã«
ãã®ããããã®ããŒãã§ã¯ãã³ã³ããŒãã³ãã®äœæãDrawableã䜿çšããæç»ãããŸããŸãªDrawableã®ç¶æ ã察話æã®èŠèŠãã£ãŒãããã¯ãã¹ã¯ããŒã«ãããªã³ã°ãžã§ã¹ãã£ãã¹ã¯ããŒã«ããŒã®äœæã«ã€ããŠæ€èšããŸããã
ãã®èšäºã¯ååã«é·ãã£ãã®ã§ãããã€ãã®éšåã«åããããšã«ããŸããã
次ã®éšåã§ã¯ã以äžã«ã€ããŠèª¬æããŸãã
- ç»é¢ãå転ããããšãã«ã³ã³ããŒãã³ãã®ç¶æ ãä¿åãã
- ãªãŒããŒã¹ã¯ããŒã«ã®ããã¯ã©ã€ããè¿œå ãã
- XMLã§ãã©ã¡ãŒã¿ãŒãæž¡ã
- ãã³ããºãŒã
ãŸããæé©åãæ¢è£œããããããã®äœ¿çšãšãã£ã³ãã¹ãžã®æç»ïŒdrawCircleãdrawTextãªã©ïŒã®éããåæç»ã®åé€ãªã©ã«ã€ããŠèª¬æãã第3éšã®èšç»ããããŸãã 2ã€ã¯èªè ãåã°ãã3ã€ç®ã®å€èŠ³ã«é¢å¿ããããŸã:)
ãã®äžé£ã®èšäºã®å®æãããããžã§ã¯ãã®ãœãŒã¹ã¯ãgithubã®goo.gl/VDeuwã«ãããŸãã ãããã¯éçºäžã®ãããžã§ã¯ãããã®åãæãã§ãããå¿ èŠã§ã¯ãªããšæãããã³ãŒããèŠã€ããå Žåã¯ãæ°ä»ããã«åãèœãšãã®ãå¿ããå¯èœæ§ããããŸãã