I have added the proper native classes on Zxing in my Android project. The camera view of zxing scan is not showing in the right size. I have added the screenshot of the camera app. The scanner part of the camera should be displayed in the middle of the screen. Currently, it is displaying in at the top right corner, which is not correct. Please help me fix this issue.
**Complete View holder Java class code is added below.**
package com.scan;
import com.google.zxing.ResultPoint;
import com.scan.camera.CameraManager;
import com.ofss.digx.mobile.android.allied.R;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import java.util.ArrayList;
import java.util.List;
public final class ViewfinderView extends View {
private static final int[] SCANNER_ALPHA = {0, 64, 128, 192, 255, 192, 128, 64};
private static final long ANIMATION_DELAY = 80L;
private static final int CURRENT_POINT_OPACITY = 0xA0;
private static final int MAX_RESULT_POINTS = 20;
private static final int POINT_SIZE = 6;
private CameraManager cameraManager;
private final Paint paint;
private Bitmap resultBitmap;
private final int maskColor;
private final int resultColor;
private final int laserColor;
private final int resultPointColor;
private int scannerAlpha;
private List<ResultPoint> possibleResultPoints;
private List<ResultPoint> lastPossibleResultPoints;
// This constructor is used when the class is built from an XML resource.
public ViewfinderView(Context context, AttributeSet attrs) {
super(context, attrs);
// Initialize these once for performance rather than calling them every time in onDraw().
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
Resources resources = getResources();
maskColor = resources.getColor(R.color.viewfinder_mask);
resultColor = resources.getColor(R.color.result_view);
laserColor = resources.getColor(R.color.viewfinder_laser);
resultPointColor = resources.getColor(R.color.possible_result_points);
scannerAlpha = 0;
possibleResultPoints = new ArrayList<>(5);
lastPossibleResultPoints = null;
}
public void setCameraManager(CameraManager cameraManager) {
this.cameraManager = cameraManager;
}
#Override
public void onDraw(Canvas canvas) {
if (cameraManager == null) {
return; // not ready yet, early draw before done configuring
}
Rect frame = cameraManager.getFramingRect();
Rect previewFrame = cameraManager.getFramingRectInPreview();
if (frame == null || previewFrame == null) {
return;
}
int width = canvas.getWidth();
int height = canvas.getHeight();
// Draw the exterior (i.e. outside the framing rect) darkened
paint.setColor(resultBitmap != null ? resultColor : maskColor);
canvas.drawRect(0, 0, width, frame.top, paint);
canvas.drawRect(0, frame.top, frame.left, frame.bottom + 1, paint);
canvas.drawRect(frame.right + 1, frame.top, width, frame.bottom + 1, paint);
canvas.drawRect(0, frame.bottom + 1, width, height, paint);
if (resultBitmap != null) {
// Draw the opaque result bitmap over the scanning rectangle
paint.setAlpha(CURRENT_POINT_OPACITY);
canvas.drawBitmap(resultBitmap, null, frame, paint);
} else {
// Draw a red "laser scanner" line through the middle to show decoding is active
paint.setColor(laserColor);
paint.setAlpha(SCANNER_ALPHA[scannerAlpha]);
scannerAlpha = (scannerAlpha + 1) % SCANNER_ALPHA.length;
int middle = frame.height() / 2 + frame.top;
canvas.drawRect(frame.left + 2, middle - 1, frame.right - 1, middle + 2, paint);
float scaleX = frame.width() / (float) previewFrame.width();
float scaleY = frame.height() / (float) previewFrame.height();
List<ResultPoint> currentPossible = possibleResultPoints;
List<ResultPoint> currentLast = lastPossibleResultPoints;
int frameLeft = frame.left;
int frameTop = frame.top;
if (currentPossible.isEmpty()) {
lastPossibleResultPoints = null;
} else {
possibleResultPoints = new ArrayList<>(5);
lastPossibleResultPoints = currentPossible;
paint.setAlpha(CURRENT_POINT_OPACITY);
paint.setColor(resultPointColor);
synchronized (currentPossible) {
for (ResultPoint point : currentPossible) {
canvas.drawCircle(frameLeft + (int) (point.getX() * scaleX),
frameTop + (int) (point.getY() * scaleY),
POINT_SIZE, paint);
}
}
}
if (currentLast != null) {
paint.setAlpha(CURRENT_POINT_OPACITY / 2);
paint.setColor(resultPointColor);
synchronized (currentLast) {
float radius = POINT_SIZE / 2.0f;
for (ResultPoint point : currentLast) {
canvas.drawCircle(frameLeft + (int) (point.getX() * scaleX),
frameTop + (int) (point.getY() * scaleY),
radius, paint);
}
}
}
// Request another update at the animation interval, but only repaint the laser line,
// not the entire viewfinder mask.
postInvalidateDelayed(ANIMATION_DELAY,
frame.left - POINT_SIZE,
frame.top - POINT_SIZE,
frame.right + POINT_SIZE,
frame.bottom + POINT_SIZE);
}
}
public void drawViewfinder() {
Bitmap resultBitmap = this.resultBitmap;
this.resultBitmap = null;
if (resultBitmap != null) {
resultBitmap.recycle();
}
invalidate();
}
/**
* Draw a bitmap with the result points highlighted instead of the live scanning display.
*
* #param barcode An image of the decoded barcode.
*/
public void drawResultBitmap(Bitmap barcode) {
resultBitmap = barcode;
invalidate();
}
public void addPossibleResultPoint(ResultPoint point) {
List<ResultPoint> points = possibleResultPoints;
synchronized (points) {
points.add(point);
int size = points.size();
if (size > MAX_RESULT_POINTS) {
// trim it
points.subList(0, size - MAX_RESULT_POINTS / 2).clear();
}
}
}
}
----------
**XML Code is added below**
<?xml version="1.0" encoding="UTF-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<SurfaceView android:id="#+id/preview_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<com.scan.ViewfinderView
android:id="#+id/viewfinder_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<TextView
android:id="#+id/status_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:background="#color/transparent"
android:text="#string/msg_default_status"
android:textColor="#color/status_text"
android:textSize="14sp"/>
</FrameLayout>
Related
I am using the framework that is described in the (great) book Beginning Android Games by Mario Zechner and Robert Green. So far all has been going great, where I can utilize the framework to draw my bitmaps for the main menu. With the framework, I am also able to clear the background, which also works great. However, when it comes to drawing pixels, lines, or shapes in general, I am completely stuck as they are not drawn. The methods execute in a similar fashion to that of the two working methods and my debugging with logging has told me that they do execute, however nothing new appears on the screen.
One source( canvas.drawLine() not appearing on bitmap ) said to draw onto a bitmap and then draw the bitmap onto the canvas, but I already made sure to do this. My paint is not null either. When drawing a rectangle, I made sure that its height and width were greater than 0. When drawing a line, I tried setting a width to 10 and the fill the STROKE. However, all of this was in vain.
Here is the code for the graphics class
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.graphics.RectF;
import com.learnplex.framework.Graphics;
import com.learnplex.framework.Pixmap;
import java.io.IOException;
import java.io.InputStream;
public class AndroidGraphics implements Graphics {
AssetManager assets;
Bitmap frameBuffer;
Canvas canvas;
Paint paint;
Rect srcRect = new Rect();
Rect dstRect = new Rect();
public AndroidGraphics(AssetManager assets, Bitmap frameBuffer) {
this.assets = assets;
this.frameBuffer = frameBuffer;
this.canvas = new Canvas(frameBuffer);
this.paint = new Paint();
}
public Pixmap newPixmap(String fileName, PixmapFormat format) {
Config config = null;
if (format == PixmapFormat.RGB565)
config = Config.RGB_565;
else if (format == PixmapFormat.ARGB4444)
config = Config.ARGB_4444;
else
config = Config.ARGB_8888;
Options options = new Options();
options.inPreferredConfig = config;
InputStream in = null;
Bitmap bitmap = null;
try {
in = assets.open(fileName);
bitmap = BitmapFactory.decodeStream(in);
if (bitmap == null)
throw new RuntimeException("Couldn't load bitmap from asset '"
+ fileName + "'");
} catch (IOException e) {
throw new RuntimeException("Couldn't load bitmap from asset '"
+ fileName + "'");
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
}
}
}
if (bitmap.getConfig() == Config.RGB_565)
format = PixmapFormat.RGB565;
else if (bitmap.getConfig() == Config.ARGB_4444)
format = PixmapFormat.ARGB4444;
else
format = PixmapFormat.ARGB8888;
return new AndroidPixmap(bitmap, format);
}
public void clear(int color) {
canvas.drawRGB((color & 0xff0000) >> 16, (color & 0xff00) >> 8,
(color & 0xff));
}
public void drawPixel(int x, int y, int color) {
paint.setColor(color);
canvas.drawPoint(x, y, paint);
}
public void drawLine(int x, int y, int x2, int y2, int color) {
paint.setColor(color);
canvas.drawLine(x, y, x2, y2, paint);
}
public void drawRect(int x, int y, int width, int height, int color) {
paint.setColor(color);
paint.setStyle(Style.FILL);
canvas.drawRect(x, y, x + width - 1, y + width - 1, paint);
}
public void drawArc(int x, int y, int width, int height, int startAngle, int sweepAngle, int color) {
paint.setColor(color);
RectF oval = new RectF(x, y, x + width - 1, y + height -1);
canvas.drawArc(oval, startAngle, sweepAngle, true, paint); // true is usecenter, idk what it does yet
}
public void drawPixmap(Pixmap pixmap, int x, int y, int srcX, int srcY,
int srcWidth, int srcHeight) {
srcRect.left = srcX;
srcRect.top = srcY;
srcRect.right = srcX + srcWidth - 1;
srcRect.bottom = srcY + srcHeight - 1;
dstRect.left = x;
dstRect.top = y;
dstRect.right = x + srcWidth - 1;
dstRect.bottom = y + srcHeight - 1;
canvas.drawBitmap(((AndroidPixmap) pixmap).bitmap, srcRect, dstRect, null);
}
public void drawPixmap(Pixmap pixmap, int x, int y) {
canvas.drawBitmap(((AndroidPixmap)pixmap).bitmap, x, y, null);
}
public int getWidth() {
return frameBuffer.getWidth();
}
public int getHeight() {
return frameBuffer.getHeight();
}
}
As I said, the drawPixmap class works, as well as the clear class
And here is the relevant part of the implementation
public void present(float deltaTime){
Graphics g = game.getGraphics();
g.clear(0xffffff); //From here down works - clears background and makes white
g.drawPixmap(Assets.getTitle(), 240, 20 ); // Display title
g.drawPixmap(Assets.getStart(), 540, 300); // Display start button
g.drawPixmap(Assets.getScore(), 590, 550); // Display score button / connect with google play
g.drawPixmap(Assets.getThemeScreen(),740, 550); // Display theme screen
if(Settings.soundEnabled) // Display sound icon
g.drawPixmap(Assets.getSoundOn(), 440, 550);
else
g.drawPixmap(Assets.getSoundOff(), 440, 550);
g.drawLine(100, 200, 300, 400, 0x000000); //This does not work - draws black line
}
I've run into a wall with this basic drawRect not showing anything and I cannot figure out why.
onDraw
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
canvas.drawCircle(circle1x, circle1y, circleRadius, circlePaint);
canvas.drawCircle(circle2x, circle2y, circleRadius, circlePaint);
canvas.drawRect(rect, rectPaint);
}
setupCropping
Is running before the onDraw and is called from the View constructor to set up all the var's
private void setupCropping() {
final float scale = getContext().getResources().getDisplayMetrics().density;
circleRadius = (int) (circleRadiusDp * scale + 0.5f);
DisplayMetrics metrics = new DisplayMetrics();
((Activity) getContext()).getWindowManager().getDefaultDisplay().getMetrics(metrics);
displayX = metrics.widthPixels;
displayY = metrics.heightPixels;
cropAreaY = displayY / 3;
cropAreaX = displayX;
//Setting up the circles for adjusting
circle1x = displayX / 2;
circle1y = displayY / 2 - (cropAreaY / 2);
circle2x = displayX / 2;
circle2y = displayY / 2 + (cropAreaY / 2);
canvasPaint = new Paint();
canvasPaint.setColor(0xffffff00);
circlePaint = new Paint();
circlePaint.setColor(0xffffff00);
circlePaint.setAntiAlias(true);
rectPaint = new Paint();
rectPaint.setColor(0xffffff00);
rect = new Rect();
rect.set(0, circle1y, 0, displayY - cropAreaY - circle1y);
}
The drawCircle works perfectly and draws as I'd expect it, I've checked the numbers being given to drawRect and they are set as they should be so I really don't know what could be going wrong here.
Full View class
package com.samplersnapshoot.domiq.samplersnapshoot;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.concurrent.CountDownLatch;
/**
* Created by domix on 14.8.2015..
*/
public class CroppingView extends View {
public final String TAG = "DEBUG";
private Canvas cropCanvas;
private Bitmap canvasBitmap;
private int displayX;
private int displayY;
private int circle1x = 0;
private int circle2x = 0;
private int circle1y = 0;
private int circle2y = 0;
private int circleRadiusDp = 20;
private int circleRadius = 100;
private int cropAreaX = 0;
private int cropAreaY = 0;
private Rect rect;
private Paint canvasPaint;
private Paint circlePaint;
private Paint rectPaint;
public CroppingView(Context context, AttributeSet attrs){
super(context, attrs);
setupCropping();
}
private void setupCropping() {
final float scale = getContext().getResources().getDisplayMetrics().density;
circleRadius = (int) (circleRadiusDp * scale + 0.5f);
DisplayMetrics metrics = new DisplayMetrics();
((Activity) getContext()).getWindowManager().getDefaultDisplay().getMetrics(metrics);
displayX = metrics.widthPixels;
displayY = metrics.heightPixels;
cropAreaY = displayY / 3;
cropAreaX = displayX;
//Setting up the circles for adjusting
circle1x = displayX / 2;
circle1y = displayY / 2 - (cropAreaY / 2);
circle2x = displayX / 2;
circle2y = displayY / 2 + (cropAreaY / 2);
canvasPaint = new Paint();
canvasPaint.setColor(0xffffff00);
circlePaint = new Paint();
circlePaint.setColor(0xffffff00);
circlePaint.setAntiAlias(true);
rectPaint = new Paint();
rectPaint.setARGB(50, 135, 225, 255);
}
/*#Override
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) {
displayX = widthMeasureSpec;
displayY = heightMeasureSpec;
invalidate();
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}*/
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
//Getting bitmap
getPath myPath = new getPath();
final File myFile = myPath.getLastModifiedFile();
final CountDownLatch latch = new CountDownLatch(1);
Thread getCanvasBitmap = new Thread() {
public void run() {
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inDither = true;
opt.inPreferredConfig = Bitmap.Config.ARGB_8888;
int i = 0;
while (canvasBitmap == null && ++i < 500) {
System.gc();
Log.d(TAG, "Trying again: " + i);
canvasBitmap = BitmapFactory.decodeFile(myFile.getAbsolutePath(), opt);
}
latch.countDown();
}
};
getCanvasBitmap.start();
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
//Turning into mutable bitmap
myFile.getParentFile().mkdirs();
RandomAccessFile randomAccessFile = null;
try {
randomAccessFile = new RandomAccessFile(myFile, "rw");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
int bWidth = canvasBitmap.getWidth();
int bHeight = canvasBitmap.getHeight();
FileChannel channel = randomAccessFile.getChannel();
MappedByteBuffer map = null;
try {
map = channel.map(FileChannel.MapMode.READ_WRITE, 0, bWidth*bHeight*4);
} catch (IOException e) {
e.printStackTrace();
}
canvasBitmap.copyPixelsToBuffer(map);
canvasBitmap.recycle();
this.canvasBitmap = Bitmap.createBitmap(bWidth, bHeight, Bitmap.Config.ARGB_8888);
map.position(0);
this.canvasBitmap.copyPixelsFromBuffer(map);
try {
channel.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
randomAccessFile.close();
} catch (IOException e) {
e.printStackTrace();
}
}
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
Log.d(TAG, "Display vars:" + displayX + " " + displayY);
canvas.drawCircle(circle1x, circle1y, circleRadius, circlePaint);
canvas.drawCircle(circle2x, circle2y, circleRadius, circlePaint);
rect = new Rect();
rect.set(5, circle1y, displayX, displayY - cropAreaY - circle1y);
canvas.drawRect(rect, rectPaint);
}
}
The class is far from well coded, I have yet to integrate a lot of functionality and clean it up.
rect.set(0, circle1y, 0, displayY - cropAreaY - circle1y);
Both your left and right coordinates are 0. Go figure.
It's
rect.set(int left, int top, int right, int bottom);
EDIT:
Okay I managed to pinpoint the issue. The following line is in your View class
rect.set(5, circle1y, displayX, displayY - cropAreaY - circle1y);
Using the same calculations in your code, for a device with a 480x800 display, I'm getting the following coordinate values.
rect.set(5, 267, 480, 267);
Again, you have overlapping sides of your Rect; Both your top and bottom sides are on the same Y coordinate. This will produce a rectangle of 262 pixels wide and ZERO HEIGHT.
All you need to do is to update your coordinates calculation and supply the proper coordinates. Otherwise, your Rect should draw just fine.
I am looking for an animation liberary of code which will help me to do 360 degree animation using set of images (Around 60 images for horizontal rotation). Also images are in SDCARD and not in application.
Thank You
You can create a custom view and override onDraw(Canvas) method and draw the bitmap of desired image.
You can keep track on the current "direction" in degree and calculate which should be displayed in what location using Canvas.drawBitmap(Bitmap,Matrix,Paint).
Here's an example of moving one image according to phone orientation.
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnTouchListener;
public class SkySurfaceView extends SurfaceView implements OnTouchListener {
private static final String TAG = SkySurfaceView.class.getSimpleName();
private double viewPortX, viewPortY;
private int starX, starY;
private Bitmap target;
private int targetWidth, targetHeight;
private int vpWidth, vpHeight;
private Matrix skyMatrix, skyMatrix2;
private Matrix skyMatrix3;
private Bitmap star;
private Paint paint;
private Rect touchRect, touchRect2, touchRect3;
public SkySurfaceView(Context context, AttributeSet attr) {
super(context, attr);
viewPortX = viewPortY = 0;
skyMatrix = new Matrix();
skyMatrix2 = new Matrix();
skyMatrix3 = new Matrix();
paint = new Paint();
paint.setStrokeWidth(1);
paint.setDither(true);
paint.setColor(Color.RED);
Options opt = new Options();
opt.inSampleSize = 2;
opt.inScaled = false;
opt.inPreferredConfig = Config.RGB_565;
star = BitmapFactory.decodeResource(getResources(), R.drawable.star,
opt);
touchRect = new Rect(0, 0, star.getWidth(), star.getHeight());
touchRect2 = new Rect(0, 0, star.getWidth(), star.getHeight());
touchRect3 = new Rect(0, 0, star.getWidth(), star.getHeight());
this.setWillNotDraw(true);
setLayerType(View.LAYER_TYPE_HARDWARE, null);
this.setOnTouchListener(this);
getHolder().setFormat(PixelFormat.RGB_565);
}
public void setTarget(Bitmap b) {
target = b;
targetHeight = target.getHeight();
targetWidth = target.getWidth();
}
public void init() {
this.starX = (int) (vpWidth * Math.random()) + vpWidth;
this.starY = (int) ((vpHeight - star.getHeight()) * Math.random());
Log.i(TAG, "drawn star on " + starX + "," + starY);
Canvas c = new Canvas();
Log.i(TAG,
"target dimension is " + target.getWidth() + "x"
+ target.getHeight());
Bitmap bitmap = Bitmap.createBitmap(target.getWidth(),
target.getHeight(), Config.RGB_565);
c.setBitmap(bitmap);
c.drawBitmap(target, 0, 0, paint);
c.drawBitmap(star, starX, starY, paint);
c.drawBitmap(star, starX - targetWidth, starY, paint);
target.recycle();
setTarget(bitmap);
setWillNotDraw(false);
}
#Override
public boolean performClick() {
super.performClick();
return false;
}
/**
*
* #param x
* - [-1:1]
* #param y
* - [-1:1]
*/
public void setViewPort(double x, double y) {
viewPortX = x;
viewPortY = y;
int tempX = (int) (targetWidth * (viewPortX));
int tempY = (int) (targetHeight * (viewPortY - 1));
tempY = Math.max(tempY, -(targetHeight - vpHeight) / 2);
tempY = Math.min(tempY, +(targetHeight - vpHeight / 2));
Log.i(TAG,
String.format("%d %d , %d %d, %d %d", tempX, tempY, tempX
- targetWidth, tempY, tempX + targetWidth, tempY));
skyMatrix.reset();
skyMatrix.postTranslate(tempX, tempY);
skyMatrix2.reset();
skyMatrix2.postTranslate(tempX - targetWidth, tempY);
skyMatrix3.reset();
skyMatrix3.postTranslate(tempX + targetWidth, tempY);
int xx = (tempX + starX);
while (xx < targetWidth) {
xx += targetWidth;
}
touchRect.offsetTo(xx % targetWidth, (tempY + starY) % targetHeight);
touchRect2.offsetTo(xx % targetWidth - targetWidth, (tempY + starY)
% targetHeight);
touchRect3.offsetTo(xx % targetWidth + targetWidth, (tempY + starY)
% targetHeight);
postInvalidate();
}
public void setViewportSize(int x, int y) {
vpWidth = x;
vpHeight = y;
}
#Override
protected void onDraw(Canvas c) {
super.onDraw(c);
c.drawBitmap(target, skyMatrix, paint);
c.drawBitmap(target, skyMatrix2, paint);
c.drawBitmap(target, skyMatrix3, paint);
}
#Override
public boolean onTouch(View v, MotionEvent event) {
float ex = event.getX();
float ey = event.getY();
Log.i(TAG, "touched " + ex + " " + ey);
if (touchRect.contains((int) ex, (int) ey)) {
if (listener != null) {
listener.onCaptured();
}
} else if (touchRect2.contains((int) ex, (int) ey)) {
if (listener != null) {
listener.onCaptured();
}
} else if (touchRect3.contains((int) ex, (int) ey)) {
if (listener != null) {
listener.onCaptured();
}
}
return false;
}
public void setListener(OnStarCaptureListener listener) {
this.listener = listener;
}
}
In this example, "target" is a sky image. Whenever setViewPort is called, (x and y [-1:1]), the image's drawing matrix is updated and "invalidate()" is called. The onDraw() method call will draw the "target" with offset.
I am developing small android application in which I m using my custom linear layout class. In that class i tried to draw one small triangle and tried to include it in to my linear layout but I m not able to do that. I tried it in following ways ...
#SuppressLint("DrawAllocation")
public class SimpleLin extends LinearLayout {
public String TAG = "CustomviewActivity";
LinearLayout parentLayout;
public SimpleLin(Context context)
{
super(context);
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if(inflater != null){
view = inflater.inflate(R.layout.main2, this);d.lin_llt);
parentLayout.setBackgroundResource(R.drawable.bcd);
}
}
public SimpleLin(Context context, AttributeSet attrs) {
super( context, attrs );
context1= context;
}
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Log.i("############################", "inside ondraw");
Paint p = new Paint();
p.setStyle(Style.FILL);
p.setColor(Color.RED);
Point point = new Point();
point.x = 80;
point.y = 80;
Path path = getEquilateralTriangle(point, 70, Direction.SOUTH);
Bitmap b = Bitmap.createBitmap(500, 500, Bitmap.Config.ARGB_8888);
canvas.drawPath(path, p);
}
public static Path getEquilateralTriangle(Point p1, int width, Direction direction) {
Point p2 = null, p3 = null;
if (direction == Direction.NORTH) {
p2 = new Point(p1.x + width, p1.y);
p3 = new Point(p1.x + (width / 2), p1.y - width);
}
else if (direction == Direction.SOUTH) {
p2 = new Point(p1.x + width,p1.y);
p3 = new Point(p1.x + (width / 2), p1.y + width);
}
else if (direction == Direction.EAST) {
p2 = new Point(p1.x, p1.y + width);
p3 = new Point(p1.x - width, p1.y + (width / 2));
}
else if (direction == Direction.WEST) {
p2 = new Point(p1.x, p1.y + width);
p3 = new Point(p1.x + width, p1.y + (width / 2));
}
Path path = new Path();
path.moveTo(p1.x, p1.y);
path.lineTo(p2.x, p2.y);
path.lineTo(p3.x, p3.y);
return path;
}
public enum Direction
{
NORTH, SOUTH, EAST, WEST;
}
#SuppressWarnings("deprecation")
public void initialiseImages()
{
invalidate();
}
}
I am calling initialiseImages method from my activity where i wanted to use this custom layout. So problem is that It not calling my on draw method when i use invalidate(). That's why it not drawing my triangle. and I am also confuse how to include that triangle into my parentlayout..
Is there wrong in my code..
How to draw such shapes in android...
Need help...
Thank you...
Code for Custom Linear Layout (I modified your code so its easier for you to understand)
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.Point;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.LinearLayout;
/**
* #author Atrix1987
*
*/
public class CustomView extends LinearLayout {
/**
* #param context
*/
public CustomView(Context context) {
super(context);
commonConstructor(context);
}
/**
* #param context
* #param attrs
*/
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
commonConstructor(context);
}
/**
*
*/
Paint trianglePaint;
/**
*
*/
Path trianglePath;
/**
* #param context
*/
private void commonConstructor(Context context) {
trianglePaint = new Paint();
trianglePaint.setStyle(Style.FILL);
trianglePaint.setColor(Color.RED);
Point point = new Point();
point.x = 80;
point.y = 80;
trianglePath = getEquilateralTriangle(point, 70, Direction.SOUTH);
}
#Override
protected void onDraw(Canvas canvas) {
Log.i("Sample", "inside ondraw");
//avoid creating objects in onDraw
canvas.drawPath(trianglePath, trianglePaint);
}
private Path getEquilateralTriangle(Point p1, int width, Direction direction) {
Log.i("Sample", "inside getEqui");
Point p2 = null, p3 = null;
if (direction == Direction.NORTH) {
p2 = new Point(p1.x + width, p1.y);
p3 = new Point(p1.x + (width / 2), p1.y - width);
} else if (direction == Direction.SOUTH) {
p2 = new Point(p1.x + width, p1.y);
p3 = new Point(p1.x + (width / 2), p1.y + width);
} else if (direction == Direction.EAST) {
p2 = new Point(p1.x, p1.y + width);
p3 = new Point(p1.x - width, p1.y + (width / 2));
} else if (direction == Direction.WEST) {
p2 = new Point(p1.x, p1.y + width);
p3 = new Point(p1.x + width, p1.y + (width / 2));
}
Path path = new Path();
path.moveTo(p1.x, p1.y);
path.lineTo(p2.x, p2.y);
path.lineTo(p3.x, p3.y);
return path;
}
public enum Direction {
NORTH, SOUTH, EAST, WEST;
}
}
The code for the activity (For simplicity and as a shortcut i did this, you can also specify it in the xml and just setContentView):
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
/**
* #author Atrix1987
*
*/
public class SampleActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
CustomView cv = new CustomView(getApplicationContext());
cv.setBackgroundColor(Color.WHITE);
setContentView(cv, new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
}
}
Do explore the developer site links for custom views, for more insight.
Hope this helps.
PFB the screenshot
If you are wanting a drawable you can use, try this http://looksok.wordpress.com/2013/08/24/android-triangle-arrow-defined-as-an-xml-shape/ sadly I can't claim credit
I extended ViewPager to have a moving background (seems to be a fairly popular request too)
It seems to be mostly working, the problem I have is that sometimes the whole background turns black.
This actually specifically occurs when I rotate the screen while on another page than the first one and start moving (it is still ok after the screen rotation) - when the activity restarts after the screen rotation, it restores the ViewPager to the same page as it was before.
The whole code with application is on GitHub, but here is the class of interest.
package com.matthieu;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.*;
import android.os.Build;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.Log;
import java.io.IOException;
import java.io.InputStream;
public class ViewPagerParallax extends ViewPager {
int background_id =-1;
int background_saved_id =-1;
int saved_width=-1, saved_height=-1, saved_max_num_pages =-1;
Bitmap saved_bitmap;
int max_num_pages=0;
int imageHeight;
int imageWidth;
float zoom_level;
Rect r = new Rect();
private final static String TAG="ViewPagerParallax";
public ViewPagerParallax(Context context) {
super(context);
}
public ViewPagerParallax(Context context, AttributeSet attrs) {
super(context, attrs);
}
#SuppressLint({"NewApi"})
private void set_new_background() {
if (background_id == -1)
return;
if (max_num_pages == 0)
return;
if (getWidth()==0 || getHeight()==0)
return;
if ((saved_height == getHeight()) && (saved_width == getWidth()) &&
(background_saved_id==background_id) &&
(saved_max_num_pages == max_num_pages))
return;
InputStream is;
try {
is = getContext().getResources().openRawResource(background_id);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(is, null, options);
imageHeight = options.outHeight;
imageWidth = options.outWidth;
zoom_level = ((float) imageHeight) / getHeight(); // we are always in 'fitY' mode
is.reset();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD_MR1) {
BitmapRegionDecoder brd = BitmapRegionDecoder.newInstance(is, true);
options.inJustDecodeBounds = false;
r.set(0, 0, Math.min((int) (getWidth() * ((max_num_pages + 4.0) / 5) * zoom_level), imageWidth), imageHeight);
saved_bitmap = brd.decodeRegion(r, options);
brd.recycle();
} else {
saved_bitmap = Bitmap.createBitmap(BitmapFactory.decodeStream(is), 0, 0, Math.min((int) (getWidth() * ((max_num_pages + 4.0) / 5) * zoom_level), imageWidth), imageHeight);
}
is.close();
} catch (IOException e) {
Log.e(TAG, "Cannot decode: " + e.getMessage());
background_id = -1;
return;
}
saved_height = getHeight();
saved_width = getWidth();
background_saved_id = background_id;
saved_max_num_pages = max_num_pages;
}
int current_position;
float current_offset;
#Override
protected void onPageScrolled(int position, float offset, int offsetPixels) {
super.onPageScrolled(position, offset, offsetPixels);
current_position = position;
current_offset = offset;
}
Rect src = new Rect(), dst = new Rect();
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
src.set((int) (((current_position + current_offset) * getWidth() * zoom_level) / 5 ), 0,
(int) ((((current_position + current_offset) * getWidth() * zoom_level) / 5) + (getWidth() * zoom_level)), imageHeight);
dst.set((int) ((current_position + current_offset) * getWidth()), 0, (int) ((current_position + current_offset) * getWidth()) + canvas.getWidth(), canvas.getHeight());
// still confused why we need to shift also in the destination canvas
canvas.drawBitmap(saved_bitmap, src, dst, null);
}
public void set_max_pages(int num_max_pages) {
max_num_pages = num_max_pages;
set_new_background();
}
public void setBackgroundAsset(int res_id) {
background_id = res_id;
set_new_background();
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
set_new_background();
}
}
The offset in the Canvas is calculated based on the first page being drawn... fixed the code o GitHub, now just hoping this is not something that is completely implementation dependent that would change later...