Related
I am trying to implement a Drawing Application in Android where the user should be able to select and move the drawn shapes.
Currently, I have statically drawn some rects and text on my Drawing Canvas.
I want to select (draw borders on the selected shape) and move the drawn shapes in onTouch events of the drawing canvas.
package com.android.graphics;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathEffect;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.List;
public class CanvasView extends View {
public enum Mode {
DRAW,
TEXT,
ERASER;
}
public enum Drawer {
PEN,
LINE,
RECTANGLE,
CIRCLE,
ELLIPSE,
QUADRATIC_BEZIER,
QUBIC_BEZIER;
}
private Canvas canvas = null;
private Bitmap bitmap = null;
private List<Path> pathLists = new ArrayList<Path>();
private List<Paint> paintLists = new ArrayList<Paint>();
private final Paint emptyPaint = new Paint();
private int baseColor = Color.WHITE;
// for Undo, Redo
private int historyPointer = 0;
// Flags
private Mode mode = Mode.DRAW;
private Drawer drawer = Drawer.PEN;
private boolean isDown = false;
// for Paint
private Paint.Style paintStyle = Paint.Style.STROKE;
private int paintStrokeColor = Color.BLACK;
private int paintFillColor = Color.BLACK;
private float paintStrokeWidth = 3F;
private int opacity = 255;
private float blur = 0F;
private Paint.Cap lineCap = Paint.Cap.ROUND;
private PathEffect drawPathEffect = null;
// for Text
private String text = "";
private Typeface fontFamily = Typeface.DEFAULT;
private float fontSize = 32F;
private Paint.Align textAlign = Paint.Align.RIGHT; // fixed
private Paint textPaint = new Paint();
private float textX = 0F;
private float textY = 0F;
// for Drawer
private float startX = 0F;
private float startY = 0F;
private float controlX = 0F;
private float controlY = 0F;
public CanvasView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.setup();
}
public CanvasView(Context context, AttributeSet attrs) {
super(context, attrs);
this.setup();
}
public CanvasView(Context context) {
super(context);
this.setup();
}
private void setup() {
this.pathLists.add(new Path());
this.paintLists.add(this.createPaint());
this.historyPointer++;
this.textPaint.setARGB(0, 255, 255, 255);
}
private Paint createPaint() {
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setStyle(this.paintStyle);
paint.setStrokeWidth(this.paintStrokeWidth);
paint.setStrokeCap(this.lineCap);
paint.setStrokeJoin(Paint.Join.MITER); // fixed
// for Text
if (this.mode == Mode.TEXT) {
paint.setTypeface(this.fontFamily);
paint.setTextSize(this.fontSize);
paint.setTextAlign(this.textAlign);
paint.setStrokeWidth(0F);
}
if (this.mode == Mode.ERASER) {
// Eraser
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
paint.setARGB(0, 0, 0, 0);
} else {
// Otherwise
paint.setColor(this.paintStrokeColor);
paint.setShadowLayer(this.blur, 0F, 0F, this.paintStrokeColor);
paint.setAlpha(this.opacity);
paint.setPathEffect(this.drawPathEffect);
}
return paint;
}
private Path createPath(MotionEvent event) {
Path path = new Path();
// Save for ACTION_MOVE
this.startX = event.getX();
this.startY = event.getY();
path.moveTo(this.startX, this.startY);
return path;
}
private void updateHistory(Path path) {
if (this.historyPointer == this.pathLists.size()) {
this.pathLists.add(path);
this.paintLists.add(this.createPaint());
this.historyPointer++;
} else {
// On the way of Undo or Redo
this.pathLists.set(this.historyPointer, path);
this.paintLists.set(this.historyPointer, this.createPaint());
this.historyPointer++;
for (int i = this.historyPointer, size = this.paintLists.size(); i < size; i++) {
this.pathLists.remove(this.historyPointer);
this.paintLists.remove(this.historyPointer);
}
}
}
private Path getCurrentPath() {
return this.pathLists.get(this.historyPointer - 1);
}
private void drawText(Canvas canvas) {
if (this.text.length() <= 0) {
return;
}
if (this.mode == Mode.TEXT) {
this.textX = this.startX;
this.textY = this.startY;
this.textPaint = this.createPaint();
}
float textX = this.textX;
float textY = this.textY;
Paint paintForMeasureText = new Paint();
// Line break automatically
float textLength = paintForMeasureText.measureText(this.text);
float lengthOfChar = textLength / (float) this.text.length();
float restWidth = this.canvas.getWidth() - textX; // text-align : right
int numChars = (lengthOfChar <= 0) ? 1 : (int) Math.floor((double) (restWidth / lengthOfChar)); // The number of characters at 1 line
int modNumChars = (numChars < 1) ? 1 : numChars;
float y = textY;
for (int i = 0, len = this.text.length(); i < len; i += modNumChars) {
String substring = "";
if ((i + modNumChars) < len) {
substring = this.text.substring(i, (i + modNumChars));
} else {
substring = this.text.substring(i, len);
}
y += this.fontSize;
canvas.drawText(substring, textX, y, this.textPaint);
}
}
private void onActionDown(MotionEvent event) {
switch (this.mode) {
case DRAW:
case ERASER:
if ((this.drawer != Drawer.QUADRATIC_BEZIER) && (this.drawer != Drawer.QUBIC_BEZIER)) {
// Oherwise
this.updateHistory(this.createPath(event));
this.isDown = true;
} else {
// Bezier
if ((this.startX == 0F) && (this.startY == 0F)) {
// The 1st tap
this.updateHistory(this.createPath(event));
} else {
// The 2nd tap
this.controlX = event.getX();
this.controlY = event.getY();
this.isDown = true;
}
}
break;
case TEXT:
this.startX = event.getX();
this.startY = event.getY();
break;
default:
break;
}
}
private void onActionMove(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (this.mode) {
case DRAW:
case ERASER:
if ((this.drawer != Drawer.QUADRATIC_BEZIER) && (this.drawer != Drawer.QUBIC_BEZIER)) {
if (!isDown) {
return;
}
Path path = this.getCurrentPath();
switch (this.drawer) {
case PEN:
path.lineTo(x, y);
break;
case LINE:
path.reset();
path.moveTo(this.startX, this.startY);
path.lineTo(x, y);
break;
case RECTANGLE:
path.reset();
float left = Math.min(this.startX, x);
float right = Math.max(this.startX, x);
float top = Math.min(this.startY, y);
float bottom = Math.max(this.startY, y);
path.addRect(left, top, right, bottom, Path.Direction.CCW);
break;
case CIRCLE:
double distanceX = Math.abs((double) (this.startX - x));
double distanceY = Math.abs((double) (this.startX - y));
double radius = Math.sqrt(Math.pow(distanceX, 2.0) + Math.pow(distanceY, 2.0));
path.reset();
path.addCircle(this.startX, this.startY, (float) radius, Path.Direction.CCW);
break;
case ELLIPSE:
RectF rect = new RectF(this.startX, this.startY, x, y);
path.reset();
path.addOval(rect, Path.Direction.CCW);
break;
default:
break;
}
} else {
if (!isDown) {
return;
}
Path path = this.getCurrentPath();
path.reset();
path.moveTo(this.startX, this.startY);
path.quadTo(this.controlX, this.controlY, x, y);
}
break;
case TEXT:
this.startX = x;
this.startY = y;
break;
default:
break;
}
}
private void onActionUp(MotionEvent event) {
if (isDown) {
this.startX = 0F;
this.startY = 0F;
this.isDown = false;
}
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// Before "drawPath"
canvas.drawColor(this.baseColor);
if (this.bitmap != null) {
canvas.drawBitmap(this.bitmap, 0F, 0F, emptyPaint);
}
for (int i = 0; i < this.historyPointer; i++) {
Path path = this.pathLists.get(i);
Paint paint = this.paintLists.get(i);
canvas.drawPath(path, paint);
}
this.drawText(canvas);
this.canvas = canvas;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
this.onActionDown(event);
break;
case MotionEvent.ACTION_MOVE:
this.onActionMove(event);
break;
case MotionEvent.ACTION_UP:
this.onActionUp(event);
break;
default:
break;
}
// Re draw
this.invalidate();
return true;
}
public Mode getMode() {
return this.mode;
}
public void setMode(Mode mode) {
this.mode = mode;
}
public Drawer getDrawer() {
return this.drawer;
}
public void setDrawer(Drawer drawer) {
this.drawer = drawer;
}
public boolean canUndo() {
return this.historyPointer > 1;
}
public boolean canRedo() {
return this.historyPointer < this.pathLists.size();
}
public boolean undo() {
if (canUndo()) {
this.historyPointer--;
this.invalidate();
return true;
} else {
return false;
}
}
public boolean redo() {
if (canRedo()) {
this.historyPointer++;
this.invalidate();
return true;
} else {
return false;
}
}
public void clear() {
Path path = new Path();
path.moveTo(0F, 0F);
path.addRect(0F, 0F, 3000F, 3000F, Path.Direction.CCW);
path.close();
Paint paint = new Paint();
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.FILL);
if (this.historyPointer == this.pathLists.size()) {
this.pathLists.add(path);
this.paintLists.add(paint);
this.historyPointer++;
} else {
// On the way of Undo or Redo
this.pathLists.set(this.historyPointer, path);
this.paintLists.set(this.historyPointer, paint);
this.historyPointer++;
for (int i = this.historyPointer, size = this.paintLists.size(); i < size; i++) {
this.pathLists.remove(this.historyPointer);
this.paintLists.remove(this.historyPointer);
}
}
this.text = "";
// Clear
this.invalidate();
}
public int getBaseColor() {
return this.baseColor;
}
public void setBaseColor(int color) {
this.baseColor = color;
}
public String getText() {
return this.text;
}
public void setText(String text) {
this.text = text;
}
public Paint.Style getPaintStyle() {
return this.paintStyle;
}
public void setPaintStyle(Paint.Style style) {
this.paintStyle = style;
}
public int getPaintStrokeColor() {
return this.paintStrokeColor;
}
public void setPaintStrokeColor(int color) {
this.paintStrokeColor = color;
}
public int getPaintFillColor() {
return this.paintFillColor;
}
public void setPaintFillColor(int color) {
this.paintFillColor = color;
}
public float getPaintStrokeWidth() {
return this.paintStrokeWidth;
}
public void setPaintStrokeWidth(float width) {
if (width >= 0) {
this.paintStrokeWidth = width;
} else {
this.paintStrokeWidth = 3F;
}
}
public int getOpacity() {
return this.opacity;
}
public void setOpacity(int opacity) {
if ((opacity >= 0) && (opacity <= 255)) {
this.opacity = opacity;
} else {
this.opacity = 255;
}
}
public float getBlur() {
return this.blur;
}
public void setBlur(float blur) {
if (blur >= 0) {
this.blur = blur;
} else {
this.blur = 0F;
}
}
public Paint.Cap getLineCap() {
return this.lineCap;
}
public void setLineCap(Paint.Cap cap) {
this.lineCap = cap;
}
public PathEffect getDrawPathEffect() {
return drawPathEffect;
}
public void setDrawPathEffect(PathEffect drawPathEffect) {
this.drawPathEffect = drawPathEffect;
}
public float getFontSize() {
return this.fontSize;
}
public void setFontSize(float size) {
if (size >= 0F) {
this.fontSize = size;
} else {
this.fontSize = 32F;
}
}
public Typeface getFontFamily() {
return this.fontFamily;
}
public void setFontFamily(Typeface face) {
this.fontFamily = face;
}
public Bitmap getBitmap() {
this.setDrawingCacheEnabled(false);
this.setDrawingCacheEnabled(true);
return Bitmap.createBitmap(this.getDrawingCache());
}
public Bitmap getScaleBitmap(int w, int h) {
this.setDrawingCacheEnabled(false);
this.setDrawingCacheEnabled(true);
return Bitmap.createScaledBitmap(this.getDrawingCache(), w, h, true);
}
public void drawBitmap(Bitmap bitmap) {
this.bitmap = bitmap;
this.invalidate();
}
public void drawBitmap(byte[] byteArray) {
this.drawBitmap(BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length));
}
public static byte[] getBitmapAsByteArray(Bitmap bitmap, CompressFormat format, int quality) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
bitmap.compress(format, quality, byteArrayOutputStream);
return byteArrayOutputStream.toByteArray();
}
public byte[] getBitmapAsByteArray(CompressFormat format, int quality) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
this.getBitmap().compress(format, quality, byteArrayOutputStream);
return byteArrayOutputStream.toByteArray();
}
public byte[] getBitmapAsByteArray() {
return this.getBitmapAsByteArray(CompressFormat.PNG, 100);
}
}
I used Custom Calendar to display month and date. Everything works fine but the requirement is, I should not display the past dates in current calendar.
For eg: If December 1 started in Friday, those 31, 30 should not be displayed.
This is my code which I done. So in xml, used the "CalendarPickerView" and displaying in dialog.
Reference: Github
CalendarPickerView
public class CalendarPickerView extends FrameLayout {
private CalendarNumbersView calendar;
private TextView tvCalendarCaption;
private ImageView ivPrevMonth;
private ImageView ivNextMonth;
public CalendarPickerView(Context context) {
super(context);
init();
}
public CalendarPickerView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CalendarPickerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
LayoutInflater.from(getContext()).inflate(R.layout.view_date_time_picker, this);
tvCalendarCaption = (TextView) findViewById(R.id.tvCalendarCaption);
calendar = (CalendarNumbersView) findViewById(R.id.calendar);
ivPrevMonth = (ImageView) findViewById(R.id.ivPrevMonth);
ivNextMonth = (ImageView) findViewById(R.id.ivNextMonth);
ivPrevMonth.setOnClickListener(onPrevMonthClickListener);
ivNextMonth.setOnClickListener(onNextMonthClickListener);
updateCaption();
}
public void setListener(CalendarNumbersView.DateSelectionListener listener) {
calendar.setListener(listener);
}
public CalendarNumbersView.DateSelectionListener getListener() {
return calendar.getListener();
}
private void updateCaption() {
SimpleDateFormat format = new SimpleDateFormat("MMMM yyyy", Locale.getDefault());
tvCalendarCaption.setText(format.format(calendar.getShownMonth().getTime()).toUpperCase());
}
public CalendarNumbersView getCalendar() {
return calendar;
}
private OnClickListener onPrevMonthClickListener = new OnClickListener() {
#Override
public void onClick(View v) {
Calendar prevMonth = calendar.getShownMonth();
prevMonth.add(Calendar.MONTH, -1);
calendar.setShownMonth(prevMonth);
updateCaption();
}
};
private OnClickListener onNextMonthClickListener = new OnClickListener() {
#Override
public void onClick(View v) {
Calendar nextMonth = calendar.getShownMonth();
nextMonth.add(Calendar.MONTH, 1);
calendar.setShownMonth(nextMonth);
updateCaption();
}
};
}
CalendarNumbersView
public class CalendarNumbersView extends View {
public static final int MAX_WEEKS_IN_MONTH = 6;
private float MAX_SELECTION_FINGER_SHIFT_DIST = 5.0f;
private TextPaint paint;
private int cellPadding;
private int textColor;
private int inactiveTextColor;
private int selectionTextColor;
private int cellBackgroundColor;
private int cellSelectionBackgroundColor;
private int dayNamesTextColor;
private int dayNamesBackgroundColor;
private boolean showDayNames = true;
private Locale locale = Locale.getDefault();
private Calendar selectedDate;
private Calendar shownMonth;
private DateSelectionListener listener = null;
//temporary and cache values
private int _cachedCellSideWidth = 0;
private int _cachedCellSideHeight = 0;
private Calendar _calendar = Calendar.getInstance();
private Rect _rect = new Rect();
private float _textHeight = 0;
private float _x;
private float _y;
private Typeface _boldTypeface;
private Typeface _defaultTypeface;
public interface DateSelectionListener {
void onDateSelected(Calendar selectedDate);
}
public static class CalendarDayCellCoord {
public int col;
public int row;
public CalendarDayCellCoord(int col, int row) {
this.col = col;
this.row = row;
}
}
public CalendarNumbersView(Context context) {
super(context);
init(null);
}
public CalendarNumbersView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public CalendarNumbersView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs);
}
private void init(AttributeSet attrs) {
paint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.LINEAR_TEXT_FLAG);
paint.setTextSize(getResources().getDimensionPixelSize(R.dimen.calendar_default_text_size));
textColor = getResources().getColor(R.color.calendar_default_text_color);
inactiveTextColor = getResources().getColor(R.color.calendar_default_inactive_text_color);
selectionTextColor = getResources().getColor(R.color.calendar_default_selection_text_color);
cellPadding = getResources().getDimensionPixelSize(R.dimen.calendar_default_cell_padding);
cellBackgroundColor = getResources().getColor(R.color.calendar_default_cell_background_color);
//cellSelectionBackgroundColor = getResources().getColor(R.color.calendar_default_cell_selection_background_color);
dayNamesTextColor = getResources().getColor(R.color.calendar_default_day_names_cell_text_color);
dayNamesBackgroundColor = getResources().getColor(R.color.calendar_default_day_names_cell_background_color);
TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.CalendarNumbersView);
if (ta != null) {
paint.setTextSize(ta.getDimensionPixelSize(R.styleable.CalendarNumbersView_fontSize, (int) paint.getTextSize()));
textColor = ta.getColor(R.styleable.CalendarNumbersView_textColor, textColor);
inactiveTextColor = ta.getColor(R.styleable.CalendarNumbersView_inactiveTextColor, inactiveTextColor);
selectionTextColor = ta.getColor(R.styleable.CalendarNumbersView_selectionTextColor, selectionTextColor);
cellPadding = ta.getDimensionPixelSize(R.styleable.CalendarNumbersView_cellPadding, cellPadding);
cellBackgroundColor = ta.getColor(R.styleable.CalendarNumbersView_cellBackgroundColor, cellBackgroundColor);
cellSelectionBackgroundColor = ta.getColor(R.styleable.CalendarNumbersView_cellSelectionBackgroundColor, cellSelectionBackgroundColor);
dayNamesTextColor = ta.getColor(R.styleable.CalendarNumbersView_cellDayNamesCellTextColor, dayNamesTextColor);
dayNamesBackgroundColor = ta.getColor(R.styleable.CalendarNumbersView_cellDayNamesCellBackgroundColor, dayNamesBackgroundColor);
}
selectedDate = Calendar.getInstance();
shownMonth = (Calendar) selectedDate.clone();
}
public int calculateQuadCellSideWidth() {
Rect bounds = new Rect();
String str = "WW";//widest possible cell string
paint.getTextBounds(str, 0, str.length(), bounds);
int maxWidth = bounds.width();
int maxHeight = bounds.height();
_textHeight = bounds.height();
return Math.max(maxWidth, maxHeight) + cellPadding * 2;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int quadCellSideWidth = calculateQuadCellSideWidth();
int calculatedWidth = quadCellSideWidth * shownMonth.getActualMaximum(Calendar.DAY_OF_WEEK) + getPaddingLeft() + getPaddingRight();
int calculatedHeight = quadCellSideWidth * MAX_WEEKS_IN_MONTH + getPaddingTop() + getPaddingBottom();
if (showDayNames) {
calculatedHeight += quadCellSideWidth;
}
int minimumWidth = Math.max(getSuggestedMinimumWidth(), calculatedWidth);
int minimumHeight = Math.max(getSuggestedMinimumHeight(), calculatedHeight);
int width = chooseSize(minimumWidth, widthMeasureSpec);
int height = chooseSize(minimumHeight, heightMeasureSpec);
setMeasuredDimension(width, height);
}
public int chooseSize(int size, int measureSpec) {
int result = size;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
switch (specMode) {
case MeasureSpec.UNSPECIFIED:
case MeasureSpec.AT_MOST:
result = size;
break;
case MeasureSpec.EXACTLY:
result = specSize;
break;
}
return result;
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
_cachedCellSideWidth = (w - getPaddingRight() - getPaddingLeft()) / shownMonth.getActualMaximum(Calendar.DAY_OF_WEEK);
_cachedCellSideHeight = (h - getPaddingTop() - getPaddingBottom()) / MAX_WEEKS_IN_MONTH;
super.onSizeChanged(w, h, oldw, oldh);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (showDayNames) {
setCalendarToFirstVisibleDay(_calendar);
DateFormatSymbols symbols = new DateFormatSymbols(locale);
for (int col = 0; col < _calendar.getActualMaximum(Calendar.DAY_OF_WEEK); col++) {
String str = _calendar.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.SHORT, locale);
String name = str.substring(0, str.length() - 1);
drawCell(canvas, -1, col, dayNamesTextColor, dayNamesBackgroundColor, name, true);
_calendar.add(Calendar.DAY_OF_MONTH, 1);
}
}
setCalendarToFirstVisibleDay(_calendar);
for (int row = 0; row < MAX_WEEKS_IN_MONTH; row++) {
for (int col = 0; col < _calendar.getActualMaximum(Calendar.DAY_OF_WEEK); col++) {
int textColor;
int backgroundColor;
if (_calendar.get(Calendar.DAY_OF_YEAR) == selectedDate.get(Calendar.DAY_OF_YEAR) &&
_calendar.get(Calendar.YEAR) == selectedDate.get(Calendar.YEAR)) {
textColor = selectionTextColor;
backgroundColor = cellSelectionBackgroundColor;
} else {
if (_calendar.get(Calendar.MONTH) == shownMonth.get(Calendar.MONTH)) {
textColor = this.textColor;
} else {
textColor = inactiveTextColor;
}
backgroundColor = cellBackgroundColor;
}
int day = _calendar.get(Calendar.DAY_OF_MONTH);
String str = Integer.toString(day);
drawCell(canvas, row, col, textColor, backgroundColor, str, false);
_calendar.add(Calendar.DAY_OF_MONTH, 1);
}
}
}
private void drawCell(Canvas canvas, int row, int col, int textColor, int backgroundColor, String str, boolean bold) {
getRectForCell(col, row, _rect);
paint.setColor(backgroundColor);
_rect.inset(cellPadding, cellPadding);
canvas.drawRect(_rect, paint);
_rect.inset(-cellPadding, -cellPadding);
paint.setColor(textColor);
if (bold) {
if (_boldTypeface == null) {
_boldTypeface = Typeface.create(Typeface.DEFAULT, Typeface.BOLD);
}
paint.setTypeface(_boldTypeface);
} else {
if (_defaultTypeface == null) {
_defaultTypeface = Typeface.create(Typeface.DEFAULT, Typeface.NORMAL);
}
paint.setTypeface(_defaultTypeface);
}
paint.setTextAlign(Paint.Align.CENTER);
canvas.drawText(str,
_rect.left + _cachedCellSideWidth / 2f,
_rect.top + _cachedCellSideHeight / 2f + _textHeight / 2f - paint.getFontMetrics().descent / 2,
paint);
}
private void setCalendarToFirstVisibleDay(Calendar calendar) {
calendar.setTime(shownMonth.getTime());
calendar.set(Calendar.DAY_OF_MONTH, 1);
int firstDayInWeek = calendar.getFirstDayOfWeek();
int firstDayOfWeekOfCurrentMonth = calendar.get(Calendar.DAY_OF_WEEK);
int shift;
if (firstDayInWeek > firstDayOfWeekOfCurrentMonth) {
shift = -(firstDayOfWeekOfCurrentMonth + calendar.getActualMaximum(Calendar.DAY_OF_WEEK) - firstDayInWeek);
} else {
shift = -(firstDayOfWeekOfCurrentMonth - firstDayInWeek);
}
calendar.add(Calendar.DAY_OF_MONTH, shift);
}
private void getRectForCell(int col, int row, Rect outRect) {
if (showDayNames) {
row++;
}
outRect.set(getPaddingLeft() + col * _cachedCellSideWidth,
getPaddingTop() + row * _cachedCellSideHeight,
getPaddingLeft() + col * _cachedCellSideWidth + _cachedCellSideWidth,
getPaddingTop() + row * _cachedCellSideHeight + _cachedCellSideHeight);
}
private CalendarDayCellCoord getCellForCoords(float x, float y) {
if (x < getPaddingLeft() ||
x >= getWidth() - getPaddingRight() ||
y < getPaddingTop() ||
y >= getHeight() - getPaddingBottom()) {
return null;
}
CalendarDayCellCoord coord = new CalendarDayCellCoord(
(int) (x - getPaddingLeft()) / _cachedCellSideWidth,
(int) (y - getPaddingTop()) / _cachedCellSideHeight
);
if (showDayNames) {
coord.row--;
if (coord.row < 0) {
return null;
}
}
return coord;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
_x = event.getX();
_y = event.getY();
return true;
case MotionEvent.ACTION_UP:
float x = event.getX();
float y = event.getY();
if (Math.sqrt(Math.pow(x - _x, 2) + Math.pow(y - _y, 2)) <= MAX_SELECTION_FINGER_SHIFT_DIST) {
selectDayAt(x, y);
}
return true;
default:
return super.onTouchEvent(event);
}
}
private void selectDayAt(float x, float y) {
CalendarDayCellCoord cellCoords = getCellForCoords(x, y);
if (cellCoords == null) {
return;
}
setCalendarToFirstVisibleDay(_calendar);
_calendar.add(Calendar.DAY_OF_YEAR, cellCoords.col);
_calendar.add(Calendar.WEEK_OF_MONTH, cellCoords.row);
selectedDate.setTime(_calendar.getTime());
if (listener != null) {
listener.onDateSelected(selectedDate);
}
invalidate();
}
public int getCellBackgroundColor() {
return cellBackgroundColor;
}
public void setCellBackgroundColor(int cellBackgroundColor) {
this.cellBackgroundColor = cellBackgroundColor;
invalidate();
}
public int getCellPadding() {
return cellPadding;
}
public void setCellPadding(int cellPadding) {
this.cellPadding = cellPadding;
invalidate();
}
public int getCellSelectionBackgroundColor() {
return cellSelectionBackgroundColor;
}
public void setCellSelectionBackgroundColor(int cellSelectionBackgroundColor) {
this.cellSelectionBackgroundColor = cellSelectionBackgroundColor;
invalidate();
}
public int getInactiveTextColor() {
return inactiveTextColor;
}
public void setInactiveTextColor(int inactiveTextColor) {
this.inactiveTextColor = inactiveTextColor;
invalidate();
}
public DateSelectionListener getListener() {
return listener;
}
public void setListener(DateSelectionListener listener) {
this.listener = listener;
}
public Calendar getSelectedDate() {
return selectedDate;
}
public void setSelectedDate(Calendar selectedDate) {
this.selectedDate = selectedDate;
invalidate();
}
public int getSelectionTextColor() {
return selectionTextColor;
}
public void setSelectionTextColor(int selectionTextColor) {
this.selectionTextColor = selectionTextColor;
invalidate();
}
public int getTextColor() {
return textColor;
}
public void setTextColor(int textColor) {
this.textColor = textColor;
invalidate();
}
public Calendar getShownMonth() {
return shownMonth;
}
public void setShownMonth(Calendar shownMonth) {
this.shownMonth = shownMonth;
invalidate();
}
public boolean isShowDayNames() {
return showDayNames;
}
public void setShowDayNames(boolean showDayNames) {
this.showDayNames = showDayNames;
invalidate();
}
public Locale getLocale() {
return locale;
}
public void setLocale(Locale locale) {
this.locale = locale;
invalidate();
}
public int getDayNamesBackgroundColor() {
return dayNamesBackgroundColor;
}
public void setDayNamesBackgroundColor(int dayNamesBackgroundColor) {
this.dayNamesBackgroundColor = dayNamesBackgroundColor;
invalidate();
}
public int getDayNamesTextColor() {
return dayNamesTextColor;
}
public void setDayNamesTextColor(int dayNamesTextColor) {
this.dayNamesTextColor = dayNamesTextColor;
invalidate();
}
}
My output:
Required output: (You can see where july dates are hidden)
You can do this by two way by changing in onDraw of CalendarNumbersView:
1: Simply change inactiveTextColor text color to transparent like
textColor = inactiveTextColor; to
textColor = Color.parseColor("#FFFFFFFF");
OR
2: Add a condition in onDraw method like below before we get day value.
if (_calendar.get(Calendar.MONTH) == shownMonth.get(Calendar.MONTH)) {
int day = _calendar.get(Calendar.DAY_OF_MONTH);
String str = Integer.toString(day);
drawCell(canvas, row, col, textColor, backgroundColor, str, false);
}
_calendar.add(Calendar.DAY_OF_MONTH, 1);
Trying to make a motion detection app based on this project. The intention is to make the app take pictures when motion is detected by comparing two images. Up to this part, the app is working fine.
Requirement:
To specify area of detection by a custom view. So that, the pictures will be captured only if a motion is detected inside the defined area by calculating the detection area.
What I have done so far:
Created a movable custom view, like a crop view of which the dimensions (Rect) are saved in the preference each time when the view is moved.
What is not working:
The motion detection from inside the custom view is not working. I believe that the bitmaps must be cropped according to the size of the custom view to do the comparison.
In the detection thread I tried setting the width and height from the preference like :
private int width = Prefe.DetectionArea.width();
private int height = Prefe.DetectionArea.height();
But it didn't work. Please help me by explaining how this could be achieved so that the motion detection will happen according to the size of the custom view. Any help is appreciated.
Project Source Code: https://drive.google.com/drive/folders/0B7-oKqt7w49mbTR6VWZYVURmVms
MotionDetectionActivity.java
public class MotionDetectionActivity extends SensorsActivity {
private static final String TAG = "MotionDetectionActivity";
private static long mReferenceTime = 0;
private static IMotionDetection detector = null;
public static MediaPlayer song;
public static Vibrator mVibrator;
private static SurfaceView preview = null;
private static SurfaceHolder previewHolder = null;
private static Camera camera = null;
private static boolean inPreview = false;
private static AreaDetectorView mDetector;
private static FrameLayout layoutDetectorArea;
static FrameLayout layoutMain;
static View mView;
private static volatile AtomicBoolean processing = new AtomicBoolean(false);
/**
* {#inheritDoc}
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.main);
mVibrator = (Vibrator)this.getSystemService(VIBRATOR_SERVICE);
layoutMain=(FrameLayout)findViewById(R.id.layoutMain);
preview = (SurfaceView) findViewById(R.id.preview);
previewHolder = preview.getHolder();
previewHolder.addCallback(surfaceCallback);
previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
mView=layoutMain;
mDetector= (AreaDetectorView) findViewById(R.id.viewDetector);
layoutDetectorArea=(FrameLayout) findViewById(R.id.layoutDetectArea);
ToggleButton toggle = (ToggleButton) findViewById(R.id.simpleToggleButton);
toggle.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
// The toggle is enabled
} else {
// The toggle is disabled
}
}
});
if (Preferences.USE_RGB) {
detector = new RgbMotionDetection();
} else if (Preferences.USE_LUMA) {
detector = new LumaMotionDetection();
} else {
// Using State based (aggregate map)
detector = new AggregateLumaMotionDetection();
}
}
/**
* {#inheritDoc}
*/
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
/**dd:
* Song play # 1
* Camera callback
*
* {#inheritDoc}
*/
#Override
public void onPause() {
super.onPause();
if(song!=null && song.isPlaying())
{
song.stop();}
camera.setPreviewCallback(null);
if (inPreview) camera.stopPreview();
inPreview = false;
camera.release();
camera = null;
}
/**
* {#inheritDoc}
*/
#Override
public void onResume() {
super.onResume();
camera = Camera.open();
}
private PreviewCallback previewCallback = new PreviewCallback() {
/**
* {#inheritDoc}
*/
#Override
public void onPreviewFrame(byte[] data, Camera cam) {
if (data == null) return;
Camera.Size size = cam.getParameters().getPreviewSize();
if (size == null) return;
if (!GlobalData.isPhoneInMotion()) {
DetectionThread thread = new DetectionThread(data, size.width, size.height);
thread.start();
}
}
};
private SurfaceHolder.Callback surfaceCallback = new SurfaceHolder.Callback() {
/**
* {#inheritDoc}
*/
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
camera.setPreviewDisplay(previewHolder);
camera.setPreviewCallback(previewCallback);
} catch (Throwable t) {
Log.e("Prek", "Exception in setPreviewDisplay()", t);
}
}
/**
* {#inheritDoc}
*/
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if(camera != null) {
Camera.Parameters parameters = camera.getParameters();
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
Camera.Size size = getBestPreviewSize(width, height, parameters);
if (size != null) {
parameters.setPreviewSize(size.width, size.height);
Log.d(TAG, "Using width=" + size.width + " height=" + size.height);
}
camera.setParameters(parameters);
camera.startPreview();
inPreview = true;
}
//AreaDetectorView.InitDetectionArea();
}
/**
* {#inheritDoc}
*/
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// Ignore
}
};
private static Camera.Size getBestPreviewSize(int width, int height, Camera.Parameters parameters) {
Camera.Size result = null;
for (Camera.Size size : parameters.getSupportedPreviewSizes()) {
if (size.width <= width && size.height <= height) {
if (result == null) {
result = size;
} else {
int resultArea = result.width * result.height;
int newArea = size.width * size.height;
if (newArea > resultArea) result = size;
}
}
}
return result;
}
//***************Detection Class******************//
private final class DetectionThread extends Thread {
private byte[] data;
private int width;
private int height;
public DetectionThread(byte[] data, int width, int height) {
this.data = data;
this.width = width;
this.height = height;
}
/**
* {#inheritDoc}
*/
#Override
public void run() {
if (!processing.compareAndSet(false, true)) return;
// Log.d(TAG, "BEGIN PROCESSING...");
try {
// Previous frame
int[] pre = null;
if (Preferences.SAVE_PREVIOUS) pre = detector.getPrevious();
// Current frame (with changes)
// long bConversion = System.currentTimeMillis();
int[] img = null;
if (Preferences.USE_RGB) {
img = ImageProcessing.decodeYUV420SPtoRGB(data, width, height);
} else {
img = ImageProcessing.decodeYUV420SPtoLuma(data, width, height);
}
// Current frame (without changes)
int[] org = null;
if (Preferences.SAVE_ORIGINAL && img != null) org = img.clone();
if (img != null && detector.detect(img, width, height)) {
// The delay is necessary to avoid taking a picture while in
// the
// middle of taking another. This problem can causes some
// phones
// to reboot.
long now = System.currentTimeMillis();
if (now > (mReferenceTime + Preferences.PICTURE_DELAY)) {
mReferenceTime = now;
//mVibrator.vibrate(10);
Bitmap previous = null;
if (Preferences.SAVE_PREVIOUS && pre != null) {
if (Preferences.USE_RGB) previous = ImageProcessing.rgbToBitmap(pre, width, height);
else previous = ImageProcessing.lumaToGreyscale(pre, width, height);
}
Bitmap original = null;
if (Preferences.SAVE_ORIGINAL && org != null) {
if (Preferences.USE_RGB) original = ImageProcessing.rgbToBitmap(org, width, height);
else original = ImageProcessing.lumaToGreyscale(org, width, height);
}
Bitmap bitmap = null;
if (Preferences.SAVE_CHANGES) {
if (Preferences.USE_RGB) bitmap = ImageProcessing.rgbToBitmap(img, width, height);
else bitmap = ImageProcessing.lumaToGreyscale(img, width, height);
}
Log.i(TAG, "Saving.. previous=" + previous + " original=" + original + " bitmap=" + bitmap);
Looper.prepare();
new SavePhotoTask().execute(previous, original, bitmap);
} else {
Log.i(TAG, "Not taking picture because not enough time has passed since the creation of the Surface");
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
processing.set(false);
}
// Log.d(TAG, "END PROCESSING...");
processing.set(false);
}
};
private static final class SavePhotoTask extends AsyncTask<Bitmap, Integer, Integer> {
/**
* {#inheritDoc}
*/
#Override
protected Integer doInBackground(Bitmap... data) {
for (int i = 0; i < data.length; i++) {
Bitmap bitmap = data[i];
String name = String.valueOf(System.currentTimeMillis());
if (bitmap != null) save(name, bitmap);
}
return 1;
}
private void save(String name, Bitmap bitmap) {
File photo = new File(Environment.getExternalStorageDirectory(), name + ".jpg");
if (photo.exists()) photo.delete();
try {
FileOutputStream fos = new FileOutputStream(photo.getPath());
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.close();
} catch (java.io.IOException e) {
Log.e("PictureDemo", "Exception in photoCallback", e);
}
}
}
}
AreaDetectorView.java
public class AreaDetectorView extends LinearLayout {
public static int Width;
public static int Height;
private static Paint BoxPaint = null;
private static Paint TextPaint = null;
private static Paint ArrowPaint = null;
private static Path mPath = null;
private static Rect mRect = null;
private static int lastX, lastY = 0;
private static boolean mBoxTouched = false;
private static boolean mArrowTouched = false;
private static Context mContext;
private static int ArrowWidth = 0;
private static Paint BoxPaint2 = null;
public AreaDetectorView(Context context) {
super(context);
mContext = context;
}
//attrs was not there
public AreaDetectorView(Context context, AttributeSet attrs) {
super(context,attrs);
mContext = context;
// TODO Auto-generated constructor stub
if (!this.getRootView().isInEditMode()) {
ArrowWidth =GetDisplayPixel(context, 30);
}
//InitDetectionArea();
InitMemberVariables();
setWillNotDraw(false);
}
public static int GetDisplayPixel(Context paramContext, int paramInt)
{
return (int)(paramInt * paramContext.getResources().getDisplayMetrics().density + 0.5F);
}
public static void InitMemberVariables() {
if (BoxPaint == null) {
BoxPaint = new Paint();
BoxPaint.setAntiAlias(true);
BoxPaint.setStrokeWidth(2.0f);
//BoxPaint.setStyle(Style.STROKE);
BoxPaint.setStyle(Style.FILL_AND_STROKE);
BoxPaint.setColor(ContextCompat.getColor(mContext, R.color.bwff_60));
}
if (ArrowPaint == null) {
ArrowPaint = new Paint();
ArrowPaint.setAntiAlias(true);
ArrowPaint.setColor(ContextCompat.getColor(mContext,R.color.redDD));
ArrowPaint.setStyle(Style.FILL_AND_STROKE);
}
if (TextPaint == null) {
TextPaint = new Paint();
TextPaint.setColor(ContextCompat.getColor(mContext,R.color.yellowL));
TextPaint.setTextSize(16);
//txtPaint.setTypeface(lcd);
TextPaint.setStyle(Style.FILL_AND_STROKE);
}
if (mPath == null) {
mPath = new Path();
} else {
mPath.reset();
}
if (mRect == null) {
mRect = new Rect();
}
if (BoxPaint2 == null) {
BoxPaint2 = new Paint();
BoxPaint2.setAntiAlias(true);
BoxPaint2.setStrokeWidth(2.0f);
//BoxPaint.setStyle(Style.STROKE);
BoxPaint2.setStyle(Style.STROKE);
BoxPaint2.setColor(ContextCompat.getColor(mContext,R.color.bwff_9e));
}
}
public static void InitDetectionArea() {
try {
int w = Prefe.DetectionArea.width();
int h = Prefe.DetectionArea.height();
int x = Prefe.DetectionArea.left;
int y = Prefe.DetectionArea.top;
// ver 2.6.0
if (Prefe.DetectionArea.left == 1
&& Prefe.DetectionArea.top == 1
&& Prefe.DetectionArea.right == 1
&& Prefe.DetectionArea.bottom == 1) {
w = Prefe.DisplayWidth / 4;
h = Prefe.DisplayHeight / 3;
// ver 2.5.9
w = Width / 4;
h = Height / 3;
Prefe.DetectorWidth = w; //UtilGeneralHelper.GetDisplayPixel(this, 100);
Prefe.DetectorHeight = h; //UtilGeneralHelper.GetDisplayPixel(this, 100);
x = (Prefe.DisplayWidth / 2) - (w / 2);
y = (Prefe.DisplayHeight / 2) - (h / 2);
// ver 2.5.9
x = (Width / 2) - (w / 2);
y = (Height / 2) - (h / 2);
}
//Prefe.DetectionArea = new Rect(x, x, x + Prefe.DetectorWidth, x + Prefe.DetectorHeight);
Prefe.DetectionArea = new Rect(x, y, x + w, y + h);
Prefe.gDetectionBitmapInt = new int[Prefe.DetectionArea.width() * Prefe.DetectionArea.height()];
Prefe.gDetectionBitmapIntPrev = new int[Prefe.DetectionArea.width() * Prefe.DetectionArea.height()];
} catch (Exception e) {
e.printStackTrace();
}
}
public static void SetDetectionArea(int x, int y, int w, int h) {
try {
Prefe.DetectionArea = new Rect(x, y, w, h);
} catch (Exception e) {
e.printStackTrace();
}
}
private void DrawAreaBox(Canvas canvas) {
try {
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
protected void dispatchDraw(Canvas canvas) {
try {
if (this.getRootView().isInEditMode()) {
super.dispatchDraw(canvas);
return;
}
//canvas.save(Canvas.MATRIX_SAVE_FLAG);
//Prefe.DetectionAreaOrient = UtilGeneralHelper.GetDetectRectByOrientation();
canvas.drawColor(0);
mPath.reset();
canvas.drawRect(Prefe.DetectionArea, BoxPaint);
mPath.moveTo(Prefe.DetectionArea.right - ArrowWidth, Prefe.DetectionArea.bottom);
mPath.lineTo(Prefe.DetectionArea.right, Prefe.DetectionArea.bottom - ArrowWidth);
mPath.lineTo(Prefe.DetectionArea.right, Prefe.DetectionArea.bottom);
mPath.lineTo(Prefe.DetectionArea.right - ArrowWidth, Prefe.DetectionArea.bottom);
mPath.close();
canvas.drawPath(mPath, ArrowPaint);
mPath.reset();
//canvas.drawRect(Prefe.DetectionAreaOrient, BoxPaint2);
//canvas.drawRect(Prefe.DetectionAreaOrientPort, BoxPaint2);
TextPaint.setTextSize(16);
//TextPaint.setLetterSpacing(2);
TextPaint.setColor(ContextCompat.getColor(mContext,R.color.bwff));
TextPaint.getTextBounds(getResources().getString(R.string.str_detectarea), 0, 1, mRect);
canvas.drawText(getResources().getString(R.string.str_detectarea),
Prefe.DetectionArea.left + 4,
Prefe.DetectionArea.top + 4 + mRect.height(),
TextPaint);
int recH = mRect.height();
TextPaint.setStrokeWidth(1.2f);
TextPaint.setTextSize(18);
TextPaint.setColor(ContextCompat.getColor(mContext,R.color.redD_9e));
TextPaint.getTextBounds(getResources().getString(R.string.str_dragandmove), 0, 1, mRect);
canvas.drawText(getResources().getString(R.string.str_dragandmove),
Prefe.DetectionArea.left + 4,
Prefe.DetectionArea.top + 20 + mRect.height()*2,
TextPaint);
TextPaint.getTextBounds(getResources().getString(R.string.str_scalearea), 0, 1, mRect);
canvas.drawText(getResources().getString(R.string.str_scalearea),
Prefe.DetectionArea.left + 4,
Prefe.DetectionArea.top + 36 + mRect.height()*3,
TextPaint);
super.dispatchDraw(canvas);
//canvas.restore();
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
protected void onDraw(Canvas canvas) {
try {
super.onDraw(canvas);
invalidate();
} catch (Exception e) {
e.printStackTrace();
} finally {
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
boolean retValue = true;
int X = (int)event.getX();
int Y = (int)event.getY();
//AppMain.txtLoc.setText(String.valueOf(X) + ", " + String.valueOf(Y));
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mBoxTouched = TouchedInBoxArea(X, Y);
//AppMain.txtLoc.setText("BoxTouched: " + String.valueOf(mBoxTouched));
if (!mBoxTouched) break;
lastX = X;
lastY = Y;
BoxPaint.setStyle(Style.FILL_AND_STROKE);
BoxPaint.setColor(ContextCompat.getColor(mContext,R.color.redD_9e));
mArrowTouched = TouchedInArrow(X, Y);
//AppMain.txtLoc.setText("ArrowTouched: " + String.valueOf(mBoxTouched));
if (mArrowTouched) {
ArrowPaint.setColor(ContextCompat.getColor(mContext,R.color.bwff_9e));
}
break;
case MotionEvent.ACTION_MOVE:
if (!mBoxTouched) break;
int moveX = X - lastX;
int moveY = Y - lastY;
//AppMain.txtLoc.setText("Move X, Y: " + String.valueOf(moveX) + "," + String.valueOf(moveY));
if (!mArrowTouched) {
if (Prefe.DetectionArea.left + moveX < 0) {
break;
}
// if (Prefe.DetectionArea.right + moveX > Prefe.gDisplay.getWidth()) {
// break;
// }
// ver 2.5.9
if (Prefe.DetectionArea.right + moveX > Width) {
break;
}
if (Prefe.DetectionArea.top + moveY < 0) {
break;
}
// if (Prefe.DetectionArea.bottom + moveY > Prefe.gDisplay.getHeight()) {
// break;
// }
// ver 2.5.9
if (Prefe.DetectionArea.bottom + moveY > Height) {
break;
}
}
if (mArrowTouched) {
if ((Prefe.DetectionArea.width() + moveX) < ArrowWidth * 2){
break;
}
if ((Prefe.DetectionArea.height() + moveY) < ArrowWidth * 2) {
break;
}
Prefe.DetectionArea.right += moveX;
Prefe.DetectionArea.bottom += moveY;
//Log.i("DBG", "W,H: " + String.valueOf(Prefe.DetectionArea.width()) + "," + String.valueOf(Prefe.DetectionArea.height()));
} else {
Prefe.DetectionArea.left += moveX;
Prefe.DetectionArea.right += moveX;
Prefe.DetectionArea.top += moveY;
Prefe.DetectionArea.bottom += moveY;
}
lastX = X;
lastY = Y;
//AppMain.txtLoc.setText(String.valueOf(Prefe.DetectionArea.left) + ", " + String.valueOf(Prefe.DetectionArea.top));
break;
case MotionEvent.ACTION_UP:
mBoxTouched = false;
mArrowTouched = false;
//BoxPaint.setStyle(Style.STROKE);
BoxPaint.setStyle(Style.FILL_AND_STROKE);
BoxPaint.setColor(ContextCompat.getColor(mContext,R.color.bwff_60));
ArrowPaint.setColor(ContextCompat.getColor(mContext,R.color.redDD));
//AppMain.txtLoc.setText(String.valueOf(Prefe.DetectionArea.left) + ", " + String.valueOf(Prefe.DetectionArea.top));
if (Prefe.DetectionArea.left < 0) {
Prefe.DetectionArea.left = 0;
}
// if (Prefe.DetectionArea.right > Prefe.gDisplay.getWidth()) {
// Prefe.DetectionArea.right = Prefe.gDisplay.getWidth();
// }
// ver 2.5.9
if (Prefe.DetectionArea.right > Width) {
Prefe.DetectionArea.right = Width;
}
if (Prefe.DetectionArea.top < 0) {
Prefe.DetectionArea.top = 0;
}
// if (Prefe.DetectionArea.bottom > Prefe.gDisplay.getHeight()) {
// Prefe.DetectionArea.bottom = Prefe.gDisplay.getHeight();
// }
if (Prefe.DetectionArea.bottom > Height) {
Prefe.DetectionArea.bottom = Height;
}
Prefe.gDetectionBitmapInt = new int[Prefe.DetectionArea.width() * Prefe.DetectionArea.height()];
Prefe.gDetectionBitmapIntPrev = new int[Prefe.DetectionArea.width() * Prefe.DetectionArea.height()];
//Prefe.gDetectionBitmapInt = null;
//Prefe.gDetectionBitmapIntPrev = null;
String area = String.valueOf(Prefe.DetectionArea.left)
+ "," + String.valueOf(Prefe.DetectionArea.top)
+ "," + String.valueOf(Prefe.DetectionArea.right)
+ "," + String.valueOf(Prefe.DetectionArea.bottom);
// UtilGeneralHelper.SavePreferenceSetting(Prefe.gContext, Prefe.PREF_DETECTION_AREA_KEY, area);
//Saving the value
SharedPrefsUtils.setStringPreference(mContext.getApplicationContext(), Prefe.PREF_DETECTION_AREA_KEY, area);
Log.v("TAG", SharedPrefsUtils.getStringPreference(mContext.getApplicationContext(),Prefe.PREF_DETECTION_AREA_KEY));
break;
}
invalidate();
return retValue;
}
private boolean TouchedInBoxArea(int x, int y) {
boolean retValue = false;
try {
if (x > Prefe.DetectionArea.left && x < Prefe.DetectionArea.right) {
if (y > Prefe.DetectionArea.top && y < Prefe.DetectionArea.bottom) {
retValue = true;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return retValue;
}
private boolean TouchedInArrow(int x, int y) {
boolean retValue = false;
try {
if (x > Prefe.DetectionArea.right - ArrowWidth && x < Prefe.DetectionArea.right) {
if (y > Prefe.DetectionArea.bottom - ArrowWidth && y < Prefe.DetectionArea.bottom) {
retValue = true;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return retValue;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(width, height);
Width = width;
Height = height;
InitDetectionArea();
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// TODO Auto-generated method stub
for (int i = 0; i < this.getChildCount()-1; i++){
(this.getChildAt(i)).layout(l, t, r, b);
}
if (changed) {
// check width height
if (r != Width || b != Height) {
// size does not match
}
}
}
}
Prefe.java
public class Prefe extends Application{
...
public static final String PREF_DETECTION_AREA_KEY = "pref_detection_area_key";
}
static{
...
DetectionArea = new Rect(1, 1, 1, 1);
}
}
I am currently working on my first jump'n Run game. The initial part is already working decent, but i still get a "bug" which appears when my "colums" are moving. This only happens when "MOVE_SPEED" is 1<. I tryed it with a Timer too, same thing.
This is how it looks like:
Please have a look at the code:
...
public class Board implements Runnable, KeyListener {
JFrame frame;
ArrayList<Column> cList;
Player p;
private boolean ingame = false;
public final static int INIT_WIDTH = 600;
public final static int INIT_HEIGHT = 400;
public static int WIDTH;
public static int HEIGHT;
private final int MOVE_SPEED = 10;
//When this is 1 the problem doesnt appear!
private final int GRAVITY = -3;
private int cPlayerStayingOn;
private double playerBottom;
private double floorTop;
private boolean mR = false;
private boolean mL = false;
private boolean jump = false;
long lastLoopTime = System.nanoTime();
final int TARGET_FPS = 100;
final long OPTIMAL_TIME = 1000000000 / TARGET_FPS;
private int fps;
private int lastFpsTime;
public static double delta = 1;
public Board() {
initBoard();
initPlayer();
initColumns();
}
private void initBoard() {
frame = new JFrame("Jump'nRun");
frame.setSize(INIT_WIDTH, INIT_HEIGHT);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(null);
frame.addKeyListener(this);
cList = new ArrayList<Column>();
frame.setVisible(true);
Board.WIDTH = frame.getContentPane().getWidth();
Board.HEIGHT = frame.getContentPane().getHeight();
}
private void initColumns() {
for (int i = 0; i < 8; i++) {
cList.add(new Column(i + 1, true));
frame.add(cList.get(i));
}
}
private void initPlayer() {
p = new Player();
frame.add(p);
}
private void moveColums() {
for (Column col : cList) {
col.setLocation((int) (col.getLocation().getX() - MOVE_SPEED), 0);
}
}
private int playerStanding(double pX) {
for (int i = 0; i < 8; i++) {
if (cList.get(i).getX() <= pX
&& (cList.get(i).getX() + cList.get(i).getWidth()) >= pX) {
return i;
}
}
return -1;
}
private void movePlayer() {
// gravity
if (playerBottom < floorTop) {
p.setLocation((int) p.getLocation().getX(), (int) p.getLocation()
.getY() - GRAVITY);
}
if (mR) {
p.moveRight();
}
if (mL) {
p.moveLeft();
}
if (jump) {
p.jump();
jump = false;
}
}
private void collectData() {
this.cPlayerStayingOn = playerStanding(p.getBounds().getX()
+ p.getBounds().getWidth());
this.playerBottom = p.getBounds().getMaxY();
this.floorTop = cList.get(cPlayerStayingOn).floor.getY();
}
private void recycleColums() {
if (cList.get(0).getX() + cList.get(0).getWidth() <= 0) {
cList.remove(0);
cList.add(7, new Column(7 + 1, false));
frame.add(cList.get(7));
}
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_SPACE
|| e.getKeyCode() == KeyEvent.VK_W
|| e.getKeyCode() == KeyEvent.VK_UP) {
if (playerBottom >= floorTop) {
jump = true;
}
}
if (e.getKeyCode() == KeyEvent.VK_D
|| e.getKeyCode() == KeyEvent.VK_RIGHT) {
mR = true;
}
if (e.getKeyCode() == KeyEvent.VK_A
|| e.getKeyCode() == KeyEvent.VK_LEFT) {
mL = true;
}
}
#Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_D
|| e.getKeyCode() == KeyEvent.VK_RIGHT) {
mR = false;
}
if (e.getKeyCode() == KeyEvent.VK_A
|| e.getKeyCode() == KeyEvent.VK_LEFT) {
mL = false;
}
}
private int getFps() {
return fps;
}
private void setFps(int fps) {
this.fps = fps;
}
#Override
public void run() {
while (true) {
if (!ingame) {
ingame = true;
} else {
long now = System.nanoTime();
long updateLength = now - lastLoopTime;
lastLoopTime = now;
delta = updateLength / ((double) OPTIMAL_TIME);
lastFpsTime += updateLength;
setFps(getFps() + 1);
if (lastFpsTime >= 1000000000) {
lastFpsTime = 0;
setFps(0);
}
recycleColums();
collectData();
moveColums();
movePlayer();
try {
Thread.sleep((lastLoopTime - System.nanoTime() + OPTIMAL_TIME) / 1000000);
} catch (Exception e) {
}
}
}
}
}
and the Column Class:
...
public class Column extends JPanel {
JPanel floor;
JPanel grass;
Random rand = new Random();
private static final long serialVersionUID = 1L;
public final static int WIDTH = Board.WIDTH / 6;
public final int HEIGHT = Board.HEIGHT;
private int position;
public final static int FLOOR_H = WIDTH;
public Column(int pos, boolean init) {
this.position = pos;
setBounds((WIDTH * position) - WIDTH, 0, WIDTH, HEIGHT);
setLayout(null);
setBackground(Color.WHITE);
floor = new JPanel();
floor.setLayout(null);
floor.setBackground(Color.BLACK);
if (init) {
floor.setBounds(0, HEIGHT - FLOOR_H, WIDTH, FLOOR_H);
} else {
floor.setBounds(0,
(HEIGHT - (FLOOR_H + (FLOOR_H * rand.nextInt(2) / 2))),
WIDTH, FLOOR_H * 2);
}
grass = new JPanel();
grass.setBounds(0, 0, WIDTH, 10);
grass.setBackground(Color.GREEN);
floor.add(grass);
add(floor);
}
}
Any hints are appreciatet!
(Sorry for the bad english)
i fixed it by changing the following:
private void recycleColums() {
if (cList.get(0).getX() + cList.get(0).getWidth() <= 0) {
cList.remove(0);
cList.add(7, new Column(7 + 1, false, cList.get(6).getX()));
frame.add(cList.get(7));
}
}
...
public Column(int pos, boolean init, int lastX) {
this.position = pos;
setLayout(null);
setBackground(Color.WHITE);
floor = new JPanel();
floor.setLayout(null);
floor.setBackground(Color.BLACK);
if (init) {
setBounds((WIDTH * position) - WIDTH, 0, WIDTH, HEIGHT);
floor.setBounds(0, HEIGHT - FLOOR_H, WIDTH, FLOOR_H);
} else {
setBounds(lastX + WIDTH, 0, WIDTH, HEIGHT);
floor.setBounds(0,
(HEIGHT - (FLOOR_H + (FLOOR_H * rand.nextInt(2) / 2))),
WIDTH, FLOOR_H * 2);
}
my java applet on eclipe don't work it writes "applet intialized" but doesn't procced to "Applet started" and the applet doesn't start (just blank screen) and also there is no errors in the console window.
image: http://i.stack.imgur.com/pvalc.png
My code is about depth-first maze and the problem is in the genrate() function because when i comment it's call the program runs well
Maze.java :
import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;
public class Maze {
// Direction Variables
public static final int Direction_Up=1;
public static final int Direction_Down=2;
public static final int Direction_Right=3;
public static final int Direction_Left=4;
//
//
int width, height;
int SizeX,SizeY;
public int[] start={0,0},end={3,3};
int offset=2;
boolean[][] WallsVer = { { false,true, false ,false},
{ false,false, false ,false}, { false,false, false ,true}};
boolean[][] WallsHor ={ { true,false, false },
{ true,false, true }, { true,true, true }, { false,true, false}};
public Maze(int width, int height,int sizeX,int sizeY) {
// TODO Auto-generated constructor stub
this.width = width;
this.height = height;
SizeX = sizeX;
SizeY = sizeY;
}
//
public boolean CollisionCheck(int x,int y,int Direction){
switch(Direction){
case Direction_Up:
if(y == 0){
return false;
}else if(!WallsVer[y-1][x]){
return true;
}else{
return false;
}
case Direction_Down:
if(y==SizeY-1){
return false;
}else if(!WallsVer[y][x]){
return true;
}else{
return false;
}
case Direction_Right:
if(x==SizeX-1){
return false;
}else if(!WallsHor[y][x]){
return true;
}else{
return false;
}
case Direction_Left:
if(x == 0){
return false;
}else if(!WallsHor[y][x-1]){
return true;
}else{
return false;
}
}
return false;
}
public void update() {
}
public void paint(Graphics g) {
//draw border
g.setColor(Color.RED);
g.drawLine(0, 0, width, 0);
g.drawLine(0, height, width, height);
g.drawLine(0, 0, 0, height);
g.drawLine(width, 0, width, height);
//draw maze
g.setColor(Color.RED);
for(int j=0;j<SizeX;j++){
for(int i=0;i<(SizeY-1);i++){
if(WallsVer[i][j])
g.drawLine(j*100,(i+1)*100 , (j*100)+100,(i+1)*100 );
}
}
for(int j=0;j<(SizeX-1);j++){
for(int i=0;i<SizeY;i++){
if(WallsHor[i][j])
g.drawLine((j+1)*100, i*100,(j+1)*100, (i*100)+100);
}
}
}
public void generate(){
// horX = sizeX -1
// horY = sizeY
// verX = sizeX
// verY = sizeY -1
//set and initialize variables
int TotalCells=SizeX*SizeY, VistedCells=0;
int[] CurrentCell = start;
int[] AvaliableCells = new int[4];
int AvaliableCellsNum = 0;
int[][] stack= new int[TotalCells][2];
int stackPointer = 0;
boolean[][] map = new boolean[SizeX][SizeY];
//initialize walls
for(int j=0;j<SizeX;j++){
for(int i=0;i<(SizeY-1);i++){
WallsVer[i][j]= true;
}
}
for(int j=0;j<(SizeX-1);j++){
for(int i=0;i<SizeY;i++){
WallsHor[i][j] = true;
}
}
//initialize map
for(int j=0;j<(SizeX-1);j++){
for(int i=0;i<(SizeY-1);i++){
map[0][0]= false;
}
}
map[CurrentCell[0]][CurrentCell[1]] = true;
stack[stackPointer] = start;
VistedCells=1;
while(VistedCells < TotalCells){
// test all the walls and enter them in AvaliableCells
if(CurrentCell[0]!=0 && !map[CurrentCell[0]-1][CurrentCell[1]]){
AvaliableCells[AvaliableCellsNum] = Direction_Right;
AvaliableCellsNum++;
}
if(CurrentCell[0]!=3 && !map[CurrentCell[0]+1][CurrentCell[1]]){
AvaliableCells[AvaliableCellsNum] = Direction_Left;
AvaliableCellsNum++;
}
if(CurrentCell[1]!=0 && !map[CurrentCell[0]][CurrentCell[1]-1]){
AvaliableCells[AvaliableCellsNum] = Direction_Up;
AvaliableCellsNum++;
}
if(CurrentCell[1]!=3 && !map[CurrentCell[0]][CurrentCell[1]+1]){
AvaliableCells[AvaliableCellsNum] = Direction_Down;
AvaliableCellsNum++;
}
// randomization process
if(AvaliableCellsNum > 0){
Random RndGen = new Random();
int RndValue = RndGen.nextInt(AvaliableCellsNum);
AvaliableCellsNum = 0;
switch(AvaliableCells[RndValue]){
case Direction_Up:
WallsVer[CurrentCell[1]-1][CurrentCell[0]] = false;
CurrentCell[1]--;
map[CurrentCell[0]][CurrentCell[1]] = true;
stackPointer++;
stack[stackPointer] = CurrentCell;
VistedCells++;
break;
case Direction_Down:
WallsVer[CurrentCell[1]][CurrentCell[0]] = false;
CurrentCell[1]++;
map[CurrentCell[0]][CurrentCell[1]] = true;
stackPointer++;
stack[stackPointer] = CurrentCell;
VistedCells++;
break;
case Direction_Right:
WallsHor[CurrentCell[1]][CurrentCell[0]-1] = false;
CurrentCell[0]--;
map[CurrentCell[0]][CurrentCell[1]] = true;
stackPointer++;
stack[stackPointer] = CurrentCell;
VistedCells++;
break;
case Direction_Left:
WallsHor[CurrentCell[1]][CurrentCell[0]] = false;
CurrentCell[0]++;
map[CurrentCell[0]][CurrentCell[1]] = true;
stackPointer++;
stack[stackPointer] = CurrentCell;
VistedCells++;
break;
}
}else{
stack = popStack(stack,stackPointer);
CurrentCell = stack[stack.length-1];
}
}
end = CurrentCell;
}
private int[][] popStack(int[][] stack,int newlength){
int[][] temp = new int[newlength][2];
for(int i=0;i<newlength;i++){
temp[i] = stack[i];
}
return temp;
}
//getters and setters
public int getHeight() {
return height;
}
public int getWidth() {
return width;
}
public int getSizeX() {
return SizeX;
}
public int getSizeY() {
return SizeY;
}
public int getStartX() {
return (start[0]*(width/SizeX))+offset;
}
public int getStartY() {
return (start[1]*(height/SizeY))+offset;
}
public int getEndX() {
return (end[0]*(width/SizeX))+offset;
}
public int getEndY() {
return (end[1]*(height/SizeY))+offset;
}
public int getBlockW() {
return (width/SizeX)-(2*offset);
}
public int getBlockH() {
return (height/SizeY)-(2*offset);
}
}