Download presentation
Presentation is loading. Please wait.
1
My own View Android development Maarten Pennings 2011 oct 14
2
Views User Interface elements are known as Views – Button – TextView – … I have written my own view – NumGridView – That can be used from XML layout in activity
3
NumGridView My app contains a 5x5 grid with numbers – This is my NumGridView drawing itself When you press a grid cell it is incremented – This is activity specific (coded in a listener)
4
Activity code is simple public classextends public class NumGridActivity extends Activity { NumGridView mNumGridView; new OnCellTouchListener mNumGridView_OnCellTouchListener= new OnCellTouchListener() { @Override public @Override public void onCellTouch( NumGridView v, int x, int y ) { v.setCell(x, y, v.getCell(x,y)+1 ); } }; @Override public @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mNumGridView= (NumGridView)findViewById(R.id.numgridview); mNumGridView.setOnCellTouchListener(mNumGridView_OnCellTouchListener); }
5
Activity layout has minor twists LinearLayout <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:numgrid="http://schemas.android.com/apk/res/nl.fampennings.numgrid" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > TextView <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hint" android:textSize="10mm" /> nl.fampennings.numgrid.NumGridView <nl.fampennings.numgrid.NumGridView android:id="@+id/numgridview" android:layout_width="fill_parent" android:layout_height="fill_parent" numgrid:cellCountX="5" numgrid:cellCountY="5" /> LinearLayout
6
Required: file attrs.xml resources declare-styleable attr /declare-styleable /resources
7
Required: file NumGridView.java package package nl.fampennings.numgrid; import import android.view.View;... publicclassextends public class NumGridView extends View { // Member variables... public public NumGridView (Context context, AttributeSet attrs) {...} public public void setCell (int x, int y, int v) {...} public public int getCell (int x, int y ) {...} @Override protected @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {...} @Override protected @Override protected void onDraw (Canvas canvas) {...} // OnCellTouchListener... } Resides in same package Extends basic View class Lazy: only implemented constructor for XML Setter and Getter for cell value “Mandatory” overrides Cell touch call-back
8
Constructor public public NumGridView(Context context, AttributeSet attrs) { super(context, attrs);... // Get the xml attributes TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NumGridView); mStretch = a.getBoolean(R.styleable.NumGridView_stretch, false); mCellCountX = a.getInt(R.styleable.NumGridView_cellCountX, 8); mCellCountY = a.getInt(R.styleable.NumGridView_cellCountY, 8); a.recycle(); // Setup the grid cells new mCells= new int[mCellCountX][mCellCountY]; forfor for(int y=0; y<mCellCountY; y++) for(int x=0; x<mCellCountX; x++) mCells[x][y]= 0; } Call parent constructor Retrieve styled attribute information Lookup the attributes (pass default in case attribute is not set) “free”! Create the actual grid data array, and fill with zero’s
9
Setter and Getter public public void setCell(int x, int y, int v) { if if( ! (0<=x && x<mCellCountX) ) thrownew throw new IllegalArgumentException("setCell: x coordinate out of range"); if if( ! (0<=y && y<mCellCountY) ) thrownew throw new IllegalArgumentException("setCell: y coordinate out of range"); mCells[x][y]= v; invalidate(); } public public int getCell(int x, int y ) { if if( ! (0<=x && x<mCellCountX) ) thrownew throw new IllegalArgumentException("setCell: x coordinate out of range"); if if( ! (0<=y && y<mCellCountY) ) thrownew throw new IllegalArgumentException("setCell: y coordinate out of range"); return return mCells[x][y]; } Sort of assert (don’t know if it’s wise) Set the value Get the value Force a re-draw
10
onMeasure @Override protected @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // Extract the Ms (MesaureSpec) parameters int widthMsMode = MeasureSpec.getMode(widthMeasureSpec); int widthMsSize = MeasureSpec.getSize(widthMeasureSpec); int heightMsMode = MeasureSpec.getMode(heightMeasureSpec); int heightMsSize = MeasureSpec.getSize(heightMeasureSpec); // Determine preferred size mCellWidth = (int)Math.floor(widthMsSize / mCellCountX ); mCellHeight= (int)Math.floor(heightMsSize / mCellCountY ); mOffsetX= ( widthMsSize - mCellWidth*mCellCountX ) / 2; mOffsetY= ( heightMsSize - mCellHeight*mCellCountY ) / 2; // Must declare my size setMeasuredDimension( mOffsetX + mCellCountX*mCellWidth + mOffsetX, mOffsetY + mCellCountY*mCellHeight + mOffsetY ); } The renderer calls us with onMeasure to ask how big we want to be (sometimes passing max sizes). We must respond by calling setMeasuredDimension. Just a fragment; real code is harder
11
onDraw @Override protected @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas);... // Draw all cells for for(int y=0; y<mCellCountY; y++) { for for(int x=0; x<mCellCountX; x++) { // Get cell data int v = mCells[x][y]; int dx= x*mCellWidth+mOffsetX; int dy= y*mCellHeight+mOffsetY; // Draw a rectangle in the cell canvas.drawRect( new Rect(dx+1,dy+1,dx+mCellWidth-2,dy+mCellHeight-2), mPaintBg); // Draw value canvas.drawText( ""+v, dx+cx, dy+cy, mPaintFg); } The renderer passes us the canvas to draw ourselves on We loop over all cells, … … draw a box on the canvas, … … and draw the cell value centered in the box The ‘paint’ (created in onCreate) is our pencil (color, font style, typeface, …)
12
onCellTouchListener public interface public interface OnCellTouchListener { void onCellTouch(NumGridView v, int x, int y); } protected protected OnCellTouchListener mOnCellTouchListener; public public void setOnCellTouchListener(OnCellTouchListener listener) { mOnCellTouchListener = listener; } @Override public @Override public boolean dispatchTouchEvent(MotionEvent event) { // First dispatch calls to our cell touch listener... if if( mOnCellTouchListener!=null ) { int x=(int)(event.getX()) - mOffsetX; int y=(int)(event.getY()) - mOffsetY; if if( 0<=x && x<mCellWidth*mCellCountX && 0<=y && y<mCellHeight*mCellCountY ) { // Touch was on cell (not on padding area) mOnCellTouchListener.onCellTouch(this,x/mCellWidth,y/mCellHeight); } //... next dispatch calls from the super class return return super.dispatchTouchEvent(event); } A class local interface definition for our listener One function: touch on x,y The member variable to store the listener The Setter for the listener The NumGridView does not register itself as listener, it overrides the dispatcher. This allows our customers to register an event listener for raw coordinates. map raw (x,y) to cell (x,y) Call listener (if set, if touch was on cell) Let super class do rest of dispatching
13
THE END
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.