Android GUI : trying to draw on a canvas - android

public class Player extends ViewGroup {
private RectF rect = new RectF();
private Paint paint;
public Player(Context context,String pname) {
super(context);
setWillNotDraw(false);
paint=new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Style.FILL);
paint.setColor(getResources().getColor(R.color.red));
}
public void onDraw(Canvas canvas) {
canvas.drawRoundRect(rect, 10, 10, paint);
canvas.drawCircle(rect.centerX(), rect.centerY(), 10, paint);
//canvas.drawColor(Color.RED);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int wspec = MeasureSpec.makeMeasureSpec(
getMeasuredWidth(), MeasureSpec.EXACTLY);
int hspec = MeasureSpec.makeMeasureSpec(
getMeasuredHeight(), MeasureSpec.EXACTLY);
for(int i=0; i<getChildCount(); i++){
View v = getChildAt(i);
v.measure(wspec, hspec);
}
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
rect.set(l, t,r, b);
}
}
the third command does draw a red rectangle which bounds are the rect (l,t,r,b) = (412,415,735,754) which is given by the param rect, and for some reason, the two first commands do not do any effect on the canvas!
I have made sure the rect is an actual rectangle, as i mentioned its values were (412,415,735,754) which does make a valid rectangle, and you see how i defined the paint so why the hell wouldnt it draw?
been spending 2 hours trying to figure it out, seriously...
thanks!
BTW, the class extends ViewGroup cause it eventually meant to implement a view container..

Try this for your onLayout routine:
protected void onLayout(boolean changed, int l, int t, int r, int b) {
rect.set(0, 0, r-l, b-t);
}
This way you will create a rect with the width and height of the full layout, but whose top left point (relative to the canvas) is 0, 0.

Related

strange behavior in custom view

I want to make a view that it's width and height is always equal.
when user define a specfied height and width in xml, it chooses a smaller one.
for example:
<com.mmmmar.ControlView
android:layout_width="100dp"
android:layout_height="200dp"
android:background="#f00" />
it run well.
However, when I make width lager than height, It runs unexpectedly.
green block is something I draw on this view, red block is the background I set in xml to indicate the area of view.
<com.mmmmar.ControlView
android:layout_width="200dp"
android:layout_height="100dp"
android:background="#f00" />
here is my code
public class ControlView extends View {
private final static int DEFAULT_SIZE = 200;
private int mDrawRadius;
private Paint mPaint;
public ControlView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
// configure paint
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setDither(true);
mPaint = paint;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int size = dp2px(DEFAULT_SIZE, getContext());
int width = calculateSpec(widthMeasureSpec, size);
int height = calculateSpec(heightMeasureSpec, size);
int radius = Math.min(width, height);
// width should equal height.
setMeasuredDimension(radius, radius);
mDrawRadius = radius;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = mPaint;
paint.setColor(Color.GREEN);
paint.setStyle(Paint.Style.FILL);
canvas.drawRect(0, 0, mDrawRadius, mDrawRadius, paint);
}
public int dp2px(float dp, Context context) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dp * scale + 0.5f);
}
public int calculateSpec(int measureSpec, int defaultSize) {
int mode = View.MeasureSpec.getMode(measureSpec);
int size = View.MeasureSpec.getSize(measureSpec);
int realSize;
if (mode == View.MeasureSpec.EXACTLY) {
realSize = size;
} else {
// For Mode :UNSPECIFIED and AT_MOST
realSize = Math.min(size, defaultSize);
}
return realSize;
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int size = dp2px(DEFAULT_SIZE, getContext());
int width = calculateSpec(widthMeasureSpec, size);
int height = calculateSpec(heightMeasureSpec, size);
int radius = Math.min(width, height);
// width should equal height.
setMeasuredDimension(radius, radius);
mDrawRadius = radius;
}
You do not need to set measured dimension after calculating.
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// Your logic comes here to pick smallest border
super.onMeasure(smallest_border_that_you_pick,smallest_border_that_you_pick)
}
Would be fix your problem.

ImageViews are invisible if Viewgroups's dispatchDraw method is overwritten in android

I have written a custom view to display images dynamically inside a circle.
I have overwritten Viewgroup's dispatchDraw method to draw circle. After this the child ImageViews are not displaying on screen, if I do no override the method, then they are displaying on screen.
Here is my class:
public class CustomView extends RelativeLayout {
private Paint paint;
private View mView;
private Context context;
private void init(Context context) {
LinearLayout layout = new LinearLayout(context);
layout.setGravity(Gravity.CENTER);
layout.setOrientation(LinearLayout.VERTICAL);
// Set generic layout parameters
LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
Button button = new Button(context);
button.setText("Button!");
layout.addView(button, params); // Modify this
ImageView imageView = new ImageView(context);
imageView.setImageResource(R.drawable.coffe_selected);
layout.addView(imageView);
this.addView(layout);
}
public CustomView(Context mContext) {
super(mContext);
context = mContext;
// create the Paint and set its color
paint = new Paint();
paint.setColor(0xFF1f5b83);
init(context);
}
#Override
protected void dispatchDraw(Canvas canvas) {
int width = this.getWidth();
int height = this.getHeight();
canvas.drawCircle(width / 2, height / 2-64, 200, paint);
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
Take a look at the source code of ViewGroup and what is happening in dispatchDraw.
Just one line out of it:
more |= drawChild(canvas, transientChild, drawingTime);
as you can see, the childs are drawn there.
So if you don't call the super method of dispatchDraw, it is possible that the childs are not drawn.
Simply call:
super.dispatchDraw(canvas);

padding custom view canvas

I newbie to android and I have a question(probably dummy question ...)
I am creating a custom view by extending View element.
I start to draw and notice that my drawings is clipped a little bit at the top and left boundaries.
what should I do to solved it out?
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec){
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int chosenDimention = Math.min(widthSize, heightSize);
setMeasuredDimension(chosenDimention, chosenDimention);
Log.v(TAG, "onMeasure: "+chosenDimention);
}
public void onDraw(Canvas canvas){
drawBackground(canvas);
Log.v(TAG, "onDraw");
Canvas c = new Canvas(background);
drawPie(c);
}
private void drawPie(Canvas canvas){
int width = getWidth();
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.scale(width, width);
// drawing stuff
canvas.restore();
}

Custom view measuring

I have made a custom view - it extends View. In the onDraw() method I create a circle with a set radius. At the moment in my xml, I have the layout_width and layout_height set to wrap_content. The circle is the right size, but when I set an onClickListener I don't have to touch the circle for it to register. I can tap anywhere where there is no other view.
I think I need to do something with onMeasure or LayoutParams but I don't know what exactly.
The aim is for the onClickListener to only be called when I click the circle with the layout_width and height still being set to wrap_content.
EDIT:
This creates a square not a circle as I wanted.
Here is my code:
protected void onDraw(Canvas canvas) {
canvas.drawCircle(canvas.getWidth() /2 , canvas.getHeight() /2,
RADIUS, paint);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
widthMeasureSpec = RADIUS;
heightMeasureSpec = RADIUS;
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
}
Try this:
float mTranslateX;
float mTranslateY;
public void onDraw(Canvas canvas){
super.onDraw(canvas);
canvas.save();
canvas.translate(mTranslateX, mTranslateY);
canvas.drawCircle(0, 0, RADIUS, paint);
canvas.restore();
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
final int dia = RADIUS * 2;
int w = resolveSize(dia, widthMeasureSpec);
int h = resolveSize(dia, heightMeasureSpec);
setMeasuredDimension(w, h);
float radius = Math.min(w, h)/2F;
mTranslateX = radius;
mTranslateY = radius;
}

TouchDelegate not receiving tap events correctly

Edit: This problem was down to me passing the wrong view to the Touch Delegate...problem is resolved now....
My RelativeLayout extension enlarges the clickable area of an ImageView. The RelativeLayout is the root View of the ListView row. The problem is when tapping areas that should be delegated to the ImageView, the ListView's onItemClicked is triggered.
My code is at the end and below is an image of what the extended bounds of the ImageView should be. If I tap on blue areas that are not the image, the click is received by the ListView.
public class DelegatingRelativeLayout extends RelativeLayout {
//relevant code moved to top
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
final float density = getContext().getResources().getDisplayMetrics().density;
int extra = (int) (density * 4 + 0.5f);
Rect rect = new Rect(0, 0, mEnlargedView.getWidth(), getHeight());
rect.right += extra; //extend bounds by 4 pixels
setTouchDelegate(new TouchDelegate(rect, mEnlargedView));
mExtendedBounds = rect;
}
public void setEnlargedView(View v) {
mEnlargedView = v;
}
private static final boolean DEBUG_DRAW = true;
private View mEnlargedView;
private Rect mExtendedBounds;
//constructors removed
#Override
protected void dispatchDraw(Canvas canvas) {
if (DEBUG_DRAW) {
Paint p = new Paint();
p.setColor(Color.BLUE);
canvas.drawRect(mExtendedBounds, p);
}
super.dispatchDraw(canvas);
}
}
Ugh, I've just realized I've been passing the wrong view to the touch delegate >.< It's been working fine now.... >.<

Categories

Resources