I'm trying to draw a FrameLayout onto a canvas, but I can't get it to work. Drawing an ImageView works fine, so I'm not sure what I'm missing.
Here's an example of one way I'm trying to draw a FrameLayout:
#Override
protected void onDraw(Canvas canvas) {
Context activity = this.getContext();
FrameLayout.LayoutParams cellParams = new FrameLayout.LayoutParams(100, 100);
ImageView cloud = new ImageView(activity);
cloud.setLayoutParams(cellParams);
cloud.setImageResource(R.drawable.transparent_cloud_large);
FrameLayout gameTile = new FrameLayout(activity);
gameTile.addView(cloud);
gameTile.layout(100, 200, 200, 300);
gameTile.draw(canvas);
}
I'm also trying it without setting LayoutParams for the ImageView, and instead using: cloud.layout(0, 0, 100, 100);, but neither way works.
Here's my code for the ImageView, which does work.
#Override
protected void onDraw(Canvas canvas) {
Context activity = this.getContext();
ImageView image = new ImageView(activity);
image.setImageResource(R.drawable.transparent_cloud_large);
image.layout(100, 100, 200, 200);
image.draw(canvas);
}
Do I need to override the FrameLayout's draw method in some way? Why doesn't it work out of the box?
I see that the javadocs say "The view must have already done a full layout before this function is called." Maybe that's my problem? How do I "do a full layout" on a FrameLayout?
I got it to work. It was missing a call to measure. This is what I'm using in the end:
GameTile gameTile = square.getGameTile();
gameTile.measure((int)tilePixels, (int)tilePixels);
gameTile.layout(0, 0, 0, 0);
canvas.save();
canvas.translate(coor.getX() * tilePixels, coor.getY() * tilePixels);
gameTile.draw(canvas);
canvas.restore();
GameTile is a subclass of FrameLayout. The save, translate, and restore methods are used to position the FrameLayout on the canvas.
Related
After creating a shape i don't know how to set up an animation. The circle I create is in the center of the screen and should move to the right margin. Can someone explain how to animate it?
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Bitmap bg = Bitmap.createBitmap(480, 800, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas (bg);
paint.setAntiAlias(true);
canvas.drawCircle(canvas.getWidth()/2, (float) (canvas.getHeight()/1.8), 13, paint);
You can do a simple view animation by creating an xml with animation requirements. Apply the animation on OnViewCreated() method to the required object.
Check view animation here: https://developer.android.com/guide/topics/graphics/view-animation.html
Example: if you want to animate nfcTerminal object, then just create nfc_terminal_bounce.xml with translate and alpha properties.
Sample code:
nfcTerminal.startAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.nfc_terminal_bounce));
I'm trying to create a translucent help overlay to be displayed over my activity's main screen when the user first opens the app. I would like to highlight a button contained in the main layout (and inflated using setContentView), by "cutting out" a section of the overlay which corresponds to the position of the button, and make the cutout transparent.
The overlay is a programmatically-created view (which extends RelativeLayout) which is added to my activity's main FrameLayout, like this:
private void addHelpOverlay(){
HelpOverlay help = new HelpOverlay(this);
help.setBackgroundColor(Color.parseColor("#BB222222"));
mainLayer.addView(help);
}
public class HelpOverlay extends RelativeLayout{
public HelpOverlay(Context context){
super(context);
}
#Override
public void dispatchDraw(Canvas canvas){
canvas.drawColor(Color.parseColor("#BB222222"));
Paint mPaint = new Paint();
mPaint.setColor(0xFFFFFF);
mPaint.setAlpha(0);
mPaint.setAntiAlias(true);
canvas.drawCircle(buttonX, buttonY, 100, mPaint);
super.dispatchDraw(canvas);
}
}
The above code doesn't actually show anything, just the translucent layout with no circle cutout. I assume this is because it's just drawing a transparent circle over top of the translucent layout. I'm really struggling to accomplish this, any suggestions would be appreciated!
Try adding PorterDuff to your paint object . which will make the specific area to transparent
Paint mPaint = new Paint();
mPaint.setColor(0xFFFFFF);
mPaint.setAlpha(0);
mPaint.setAntiAlias(true);
mPaint.setColor(Color.TRANSPARENT);
mPaint.setXfermode(new PorterDuffXfermode(
PorterDuff.Mode.CLEAR));
canvas.drawCircle(buttonX, buttonY, 100, mPaint);
If you get a picth black in the circle area, that must be due to graphic rendering problem , you can enable it using below code right before you declare paint object .
if (android.os.Build.VERSION.SDK_INT >= 11) {
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
I guess this should fix your issue
I've been having a lot of issues drawing multiple paths in the same relative layout. What happens is that all my paths are drawn on the same spot they were originally drawn. Instead I want to shrink each drawn path/canvas and have them displayed side by side on the page.
My code to draw the paths looks like
for (int x=0; x < paths.size(); x++){
DrawView dw = new CustomView(this);
dw.path = paths.get(x);
dw.paint = paints.get(x);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
if (x == 0){
} else {
params.addRule(RelativeLayout.BELOW, x-1);
}
dw.setId(x);
layout.addView(dw, params);
}
I followed other suggestions for TextViews to add an custom layout parameter to display each TextView below each other but this does not appear to work for dynamically drawn paths.
Note: CustomView is a class that extends View and overwrites the onDraw method to draw out my paths.
EDIT:
If it helps my custom class looks like
public class CustomView extends View {
public Path path;
public Paint paint = new Paint();
public CustomView(Context context){
super(context);
paint.setAntiAlias(true);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
}
#Override
protected void onDraw(Canvas canvas){
canvas.drawPath(path, paint);
}
}
Is it necessary for you to use a RelativeLayout? If it is not too binding, consider having a LinearLayout which either replaces the RelativeLayout, or is contained within the RelativeLayout. Then you can add all the CustomViews to this LinearLayout, setting the weight field in LinearLayout.LayoutParams to 1.
Alternatively, consider manually setting each CustomView's height to getHeight()/(paths.size()) instead of RelativeLayout.LayoutParams.WRAP_CONTENT.
I have a canvas / surfaceview that I am drawing multiple bitmaps so that the user is able to drag around and position anywhere on the canvas. I am looking for a method to create a zoom in and out button that toggles a 50% zoom scale of the canvas when selected.
My app draws multiple bitmaps to the canvas using the onDraw() method.
I have a function now that scales each individual bitmap when the zoom button is toggled but the problem with this is getting the bitmaps to line up relative to each other after the scale. I currently have them scaled off their ending x/y position but by reducing the size 50% the items that were once near each other are no longer that way when zoomed out. I am hoping there is a solution that allows me to accomplish this with the entire canvas at once.
If I need to share some code please let me know.
SurfaceView class where all the drawing happens
public class BuildView extends SurfaceView implements SurfaceHolder.Callback {
then non-scaling drawing happens as canvas.drawBitmap(myBitmap,x,y,null);
Here is my oncreate method, note that BuildView gameView; is initating my surfaceview class;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set full screen view
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
requestWindowFeature(Window.FEATURE_NO_TITLE);
FrameLayout Game = new FrameLayout(this);
LinearLayout GameWidgets = new LinearLayout (this);
gameview = new BuildView(this, null);
//create buttons to lay over the surfaceview
Button AddItemButton = new Button(this);
//Button ZoomInButton = new Button(this);
zoomButton = new Button(this);
TextView MyText = new TextView(this);
AddItemButton.setWidth(250);
AddItemButton.setText("Add Item");
AddItemButton.setId(1);
AddItemButton.setOnClickListener(addItemHandler);
MyText.setText("test");
zoomButton.setWidth(250);
zoomButton.setText("Zoom Out");
zoomButton.setId(2);
zoomButton.setOnClickListener(zoomHandler);
// adding views to the main Game framelayout view * note the view "gameview" is the surface view that everything happens on
GameWidgets.addView(AddItemButton);
GameWidgets.addView(zoomButton);
Game.addView(gameview);
Game.addView(GameWidgets);
int w=getWindowManager().getDefaultDisplay().getWidth()-25;
int h=getWindowManager().getDefaultDisplay().getHeight()-25;
gameview.wid = w; //set width and height in view
gameview.hei = h;
gameview.setWidthHeight(w, h);
setContentView(Game); //trying this out
gameview.updateImage(0, 0); //force bg change
Log.i("views", "Added Game View");
//setContentView(v);
}
since it has been requested here is how I am currently scaling the bitmaps, note that I am looking for another method of scaling the entire canvas. Here is the specifics of my onDraw() method but the full method has more logic in regards to item placement and before scaling I check a boolean flag if the user has selected to scale but i figured you wouldn't want to sift through that much code so I am just putting the pertinent stuff here.
protected void onDraw(Canvas canvas) {
float scaleHeight = getScaled(myBitmap.getHeight());
float scaleWidth = getScaled(myBitmap.getWidth());
scaler.postTranslate(-myBitmap.getWidth() / 4, -itemBit.getHeight() / 4); // Centers image
scaler.postScale(scaleWidth, scaleHeight);
Log.e("onDraw", "item not placed - scaler.postTranslate being called");
scaler.postTranslate(itemX+myBitmap.getWidth()/2, itemY+myBitmap.getHeight()/2);
canvas.drawBitmap(myBitmap, scaler, null);
}
here is my getScaled function;
float getScaled(int orig) {
//return a scaled version
int newScale = orig /2;
float scaled = ((float) newScale) / orig;
return scaled;
}
EDIT:
OK, so I've extended the lenght and the width of the view to a big part of the screen I can assume that the onDraw() method is NOT TAKING the limits of the view, because it goes through all the screen as I can suppose. So the question now would be how to tell the canvas to respect the limits of the view? Any ideas, maybe forcing some parameters?
END OF EDIT
I have implemented some code for drawing a custom view, but the canvas is blank. I am sure it is running, because I have added log traces, and those are showing up just fine.
How do I properly implement drawing for custom views, and what is wrong with what I've done below?
My custom view that goes inside a layout like this:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/relativeLayout1" android:layout_height="fill_parent"
android:layout_width="fill_parent">
<pis.core.JMI_VistaMenuIn android:layout_height="150dip" android:layout_width="150dip" android:layout_alignParentTop="true" android:id="#+id/viewAnd01" ></pis.core.JMI_VistaMenuIn>
<Button android:layout_width="wrap_content" android:id="#+id/btnJugar" android:layout_height="wrap_content" android:text="Jugar" android:layout_below="#+id/viewAnd01" android:layout_alignLeft="#+id/viewAnd01" android:layout_alignRight="#+id/viewAnd01"></Button>
</RelativeLayout>
The customview is the one called: pis.core.JMI_VistaMenuIn. In the preview I got an "java.lang.UnsupportedOperationException" but when the .apk is loaded the xml layout WORKS.
Here is the code for my custom view. As I said before, the lines that contain the logging are getting hit, but my canvas is blank:
public class JMI_VistaMenuIn extends View {
public static final String QUOTE = "Mind Logic+";
public Animation anim;
//Default constructors
public void createAnim(Canvas canvas) {
Log.i("SC", "Exe canvas 01");
anim = new RotateAnimation(0, 360, canvas.getWidth() / 2, canvas
.getHeight() / 2);
anim.setRepeatMode(Animation.REVERSE);
anim.setRepeatCount(Animation.INFINITE);
anim.setDuration(10000L);
anim.setInterpolator(new AccelerateDecelerateInterpolator());
startAnimation(anim);
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
// creates the animation the first time
if (anim == null) {
createAnim(canvas);
}
Path circle = new Path();
int centerX = canvas.getWidth() / 2;
int centerY = canvas.getHeight() / 2;
int r = Math.min(centerX, centerY);
circle.addCircle(centerX, centerY, r, Direction.CW);
Paint paint = new Paint();
paint.setColor(Color.BLUE);
paint.setTextSize(30);
paint.setAntiAlias(true);
canvas.drawTextOnPath(QUOTE, circle, 0, 30, paint);
Log.i("SC", "Exe canvas 02");
}
}
Similar code works just fine for me, including the animation. You have another issue somewhere else in your code: try setting the paint style.
Paint paint = new Paint();
paint.setColor(Color.BLUE);
paint.setTextSize(30);
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);