I have created a custom View that will display a circle (the idea is that the user will be able to interact with this "ball" in various ways)
From my main activity class, I want to adjust some of the "ball's" properties, in this case change its color.
My problem is that nothing happens (no errors either, the app runs but doesn't do what I want) when I try to call the various methods from my MainActivity class, but if I do it from CircleView class, it works (for example changing the color upon touch)
Here is my custom View class (CircleView.java):
public class CircleView extends View {
private int circleColor = Color.GREEN;
private Paint paint;
public CircleView(Context context) {
super(context);
init(context, null);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_SCROLL:
this.circleColor = setRandomColor();
invalidate();
break;
case MotionEvent.ACTION_DOWN:
this.circleColor = setRandomColor();
invalidate();
break;
}
return super.onTouchEvent(event);
}
public CircleView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
paint = new Paint();
paint.setAntiAlias(true);
}
public void setCircleColor(int circleColor) {
this.circleColor = circleColor;
invalidate();
}
public int setRandomColor() {
Random random = new Random();
int randomColor = Color.argb(255, random.nextInt(), random.nextInt(), random.nextInt());
return randomColor;
}
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//...
//someXvalue, someYvalue, someRadius are being set here
//...
paint.setColor(circleColor);
canvas.drawCircle(someXvalue, someYvalue, someRadius, paint);
}
}
And here is my MainActivity.java class:
public class MainActivity extends Activity implements
GestureDetector.OnGestureListener {
private GestureDetectorCompat mDetector;
CircleView circle;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDetector = new GestureDetectorCompat(this, this);
circle = new CircleView(this);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
this.mDetector.onTouchEvent(event);
return super.onTouchEvent(event);
}
#Override
public boolean onDown(MotionEvent event) {
return true;
}
#Override
public boolean onSingleTapConfirmed(MotionEvent event) {
circle.setCircleColor(circle.setRandomColor(0));
circle.invalidate();
return true;
}
}
I am new to Android development, and Java as well. I realize it could be something with the Context, which is something I have not fully understood yet. Could also be something with the TouchEvents. I am sure that someone out there can see my mistake. Any help is appreciated.
your circle view is not a part of activity's layout , it's just a object in memory which has no link to your activity screen so solutions
1.) Either set circle as Activity's view
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDetector = new GestureDetectorCompat(this, this);
circle = new CircleView(this);
setContentView(circle);
}
2.) you can create your <yourpackagename.CircleView ...attributes .../> tag in your activity_main.xml and then use findViewById to initialize it in your activity.
1)If all you want to do with gestures is on tap, just implement an onClickListener on your View instead.
2)You aren't actually using the GestureDetector anywhere. The way it works is you set an onTouchListener for the view you want to get gestures on, and send the events to the gesture detector. You aren't ever sending data for any view to the detector, so it will never do anything.
3)Not a bug just an oddness- why circle.setColor(circle.setRandomColor())? I would expect a function named setXXX to actually set XXX, rather than having to do it yourself later. Not following that convention will work, but make debugging and maintenance hard.
Edit: Also what #Pavneet_Singh said- your circle isn't in your layout anywhere, so it won't be on screen.
Related
I have generated simple black with square corners for QR code using com.google.zxing:core:3.3.3.
I want to customize QR code appearance like Instagram.
This library is used at many places https://github.com/scola/Qart
How to make square edges rounded? like below image :
You can create custom class like
private static class CustomViewFinderView extends ViewFinderView {
public final Paint PAINT = new Paint();
public CustomViewFinderView(Context context) {
super(context);
init();
}
public CustomViewFinderView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
// paint initialization
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
// Here you can draw your view using canvas with edges
}
}
After that while you initialize your ZXingScannerView add your custom view in createViewFinderView method.
ZXingScannerView mScannerView = new ZXingScannerView(this) {
#Override
protected IViewFinder createViewFinderView(Context context) {
return new CustomViewFinderView(context);
}
};
I have only a simple MyGestureOverlayView extends GestureOverlayView in my layout; I want that when the user swipes and the GestureOverlayView recognizes the gesture, it doesn't change color. I want that the color will change only when I call overlay.setGestureColor(int color), but in fact this method changes the color that will have the next gesture when recognized by the super class, not while the user is swiping.
So my question is: how can I change the color of the gesture while the user is performing the gesture?
public class MyGestureOverlayView extends GestureOverlayView implements
GestureOverlayView.OnGesturePerformedListener,
GestureOverlayView.OnGestureListener {
private static final String TAG = MyGestureOverlayView.class.getName();
private GiocoActivity mContext;
private boolean mRecognized;
private GestureLibrary gestures;
public MyGestureOverlayView(Context context, AttributeSet attrs) {
super(context, attrs);
if (context instanceof GiocoActivity)
mContext = (GiocoActivity) context;
gestures = GestureLibraries.fromRawResource(mContext, R.raw.gesture);
if (!gestures.load())
mContext.finish();
addOnGesturePerformedListener(this);
addOnGestureListener(this);
}
#Override
public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) {
ArrayList<Prediction> predictions = gestures.recognize(gesture);
Log.d(TAG, "Gesture riconosciuta!");
// Sorry for my English :)
if (predictions.size() > 0 && predictions.get(0).score > 3.0) {
overlay.setGestureColor(Color.GREEN);
// The color doesn't change here, but it will change in the next gesture
String action = predictions.get(0).name;
mRecognized = true;
Toast.makeText(mContext, action, Toast.LENGTH_SHORT).show();
}
else {
overlay.setGestureColor(Color.RED);
// The color doesn't change here, but it will change in the next gesture
mRecognized = false;
}
Log.d(TAG, "Fine riconoscimento Gesture; esito: "+ mRecognized);
}
#Override
public void onGestureStarted(GestureOverlayView overlay, MotionEvent event) {
Log.d(TAG, "Gesture iniziata!");
}
#Override
public void onGesture(GestureOverlayView overlay, MotionEvent event) {
Log.d(TAG, "Gesture in corso!");
if (mRecognized) // Always false for the first gesture
overlay.setGestureColor(Color.GREEN); // Same as before
else
overlay.setGestureColor(Color.RED); // Same as before
}
#Override
public void onGestureEnded(GestureOverlayView overlay, MotionEvent event) {
Log.d(TAG, "Gesture finita!");
}
#Override
public void onGestureCancelled(GestureOverlayView overlay, MotionEvent event) {
Log.d(TAG, "Gesture cancellata!");
}
}
Besides, the callback method onGesturePerformed is called after onGestureEnded, so the boolean mRecognized in onGesture() is always false whem I perform a gesture for the first time and when it'll be recognized from the super class it'll be displayed red in any case (both recognized or not by my onGesturePerformedListener).
Sorry if I was complicate, this is my first question, and I found only one question similar to this, but it has no answers.
Thanks for your time.
Wow, this is frustrating. I'm really just trying to clear my ImageView before each time I draw on it.
I'm trying to extend Android's ImageView class into a custom StatusBarImageView. I provide a public method setPercentComplete(float percent) so that my activity can update the image accordingly. But every time I try to update the image by invalidating it and triggering it's onDraw(Canvas canvas) method, for some reason it tries to draw the new status bar and it's text on top of the existing image rather than starting fresh. So the captions I draw using canvas.drawText(...) bleed over each other.
Can anyone please tell me why this is happening / how to fix it?
I've tried several different approaches and none of them have worked.
I tried saving before the first time I draw and restoring before each subsequent time, but apparently it's a new canvas each time the onDraw() method fires, so restore() throws an exception that there hasn't been a save().
I've tried using canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR), but not only does that not work, it changes the background to be solid black for some reason.
Here's my code:
class StatusBarImageView extends ImageView {
private float status = 100.0f;
private Canvas lastCanvas;
private Paint imagePainter = new Paint();
private Paint textPainter = new Paint();
public StatusBarImageView(Context context) {
super(context);
initializePainters();
}
public StatusBarImageView(Context context, AttributeSet attributes) {
super(context, attributes);
initializePainters();
}
public StatusBarImageView(Context context, AttributeSet attributes, int defStyle) {
super(context, attributes, defStyle);
initializePainters();
}
private void initializePainters() {
this.status = 100.0f;
this.imagePainter.setStyle(Style.FILL_AND_STROKE);
this.textPainter.setStyle(Style.FILL);
this.textPainter.setFakeBoldText(true);
}
public void setPercentComplete(float status) {
this.status = status;
this.invalidate();
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
//Erase previous status bar and its text captions before drawing new one
if(this.lastCanvas != null) {
this.lastCanvas.restore(); //throws exception
//this.lastCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); // Doesn't work and makes background black
}
canvas.save();
this.lastCanvas = canvas;
//this.canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); // Doesn't work and makes the background black
//this.canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.MULTIPLY); // Same problem
this.drawStatusBarAndCaptions(canvas); //Uses canvas.drawRect and canvas.drawText
}
//...
}
And the xml just looks like:
<my.package.name.then.StatusBarImageView
android:id="#+id/status_bar"
android:layout_width="match_parent"
android:layout_height="0dp"
android:padding="0dp"
android:layout_margin="0dp"
android:layout_weight="3"/>
But every time I try to update the image by invalidating it and triggering it's onDraw(Canvas canvas) method.
Well, that's the way it should work. Any invalidate() would eventually cause onDraw() to be called.
In order to achieve the requirement you have, you may keep a boolean value, which will indicate you whether current onDraw() is initiated after setPercentComplete() call:
private boolean flag = false;
public void setPercentComplete(float status) {
this.status = status;
this.flag = true;
this.invalidate();
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (flag) {
flag = false;
// perform actions for showing percent status
} else {
// draw other stuff
}
}
The answer for this question was useful for me. But I have a new question about that. I read the Java grammar but I have problems in some part of the Java grammar and for this reason, I ask my questions here. I changed two part of the code link as the following:
In Draw.java:
I changed the public void onDraw(Canvas canvas) To the public void d(Canvas canvas)
And I added the following in MainActivity.java
public class MainActivity extends Activity {
Draw draw;
Cal cal;
TextView textView;
RelativeLayout linearLayout;
Canvas canvas;
public void onCreate(Bundle s) {
super.onCreate(s);
setContentView(R.layout.activity_main);
linearLayout = (RelativeLayout) findViewById(R.id.t);
cal = new Cal(this);
cal.cal();
textView = new TextView(getApplicationContext());
textView.setText("" + cal.result);
textView.setTextColor(Color.RED);
draw = new Draw(this);
draw.d(canvas);
linearLayout.addView(textView);
linearLayout.addView(draw);
}}
the code can compile and install successfully.But only it can run for a short time in my device and also it can not run in AVD manager.
I'm sure the grammar used is correct.But I do not know what is the cause of the collision in the code that I can not see the output Code correctly.
UPDATE, Draw.java
public class Draw extends View {
Paint paint = new Paint();
Draw(Context context) {
super(context);
}
public void d(Canvas canvas) {
paint.setColor(Color.BLUE);
canvas.drawCircle(120,120,40,paint);
}
}
I don't try it, maybe it's stupid but try to add public front of the Draw constructor:
**public** Draw(Context context) {
super(context);
}
And in d() method, there should be one less parenthesis.
I have a FrameLayout containing two SurfaceViews. One of them will show the camera preview, and the other is a custom surface view I use for drawing. Problem is the surface view does not show up. If I comment out the line where the camera starts preview, it does though, on the black background. This indicates me that the Surface view is positioned well, but I suspect that when the camera preview draws, something goes wrong.
The camera view:
public CameraView(Context context, AttributeSet a) {
super(context, a);
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
The custom view:
public InclinaisonGauge(Context context, AttributeSet attrs) {
super(context, attrs);
getHolder().addCallback(this);
getHolder().setFormat(PixelFormat.TRANSLUCENT);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
run = true;
updateThread = new Thread()
{
public void run()
{
Canvas c = null;
final SurfaceHolder inclHolder = getHolder();
while (run) {
try {
c = inclHolder.lockCanvas();
if(c!=null)
{
synchronized (inclHolder) {
onDraw(c);
}
}
} finally {
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
inclHolder.unlockCanvasAndPost(c);
}
}
}
}
};
And I use this very simple draw method on the custom view to make sure it is not a framerate issue
public void doDraw(final Canvas canvas, final boolean bigSize, float daDirection)
{
canvas.drawARGB(255, 255, 255, 255);
}
Has anyone experienced this?
Thanks
Ok, if anyone else gets this, solution is to call this on the surfaceView
this.setZOrderMediaOverlay(true);
I don't think SurfaceViews are intended to be used as an overlay, but it is possible to achieve this behavior. What you have to do is when the SurfaceView class is created:
setZOrderMediaOverlay(true);
getHolder().setFormat(PixelFormat.TRANSPARENT);