I have created a circle in custom view. I want to add 6 colors to it based on a condition. The 6 regions will keep changing based on the condition. For eg, each region can vary from 30 degrees to 90 degrees to 120 degrees.
My question is
1) How do I add 6 colors to the circle. Please note that I cannot divide the circle into 6 equal regions, thats not how it is supposed to be.
2) How do I assign the starting and ending points of the regions. For example if I want to add green color from 45degrees to 90 degrees. How do I do this?
The end product is supposed to look as below
package com.example.submission_customclock;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.BroadcastReceiver;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.CountDownTimer;
import android.os.Handler;
import android.text.format.Time;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.RemoteViews.RemoteView;
import java.util.TimeZone;
/**
* This widget display an analogic clock with two hands for hours and
* minutes.
*
* #attr ref android.R.styleable#AnalogClock_dial
* #attr ref android.R.styleable#AnalogClock_hand_hour
* #attr ref android.R.styleable#AnalogClock_hand_minute
*/
#RemoteView
public class AnalogClock extends View {
private Time mCalendar;
private static final String DEBUGTAG = "FA";
private Drawable mHourHand;
private Drawable mMinuteHand;
private Drawable mSecondHand;
private Drawable mDial;
private Drawable mDial_frame;
private Drawable mDial_center;
private int mDialWidth;
private int mDialHeight;
private boolean mAttached;
private final Handler mHandler = new Handler();
private float mMinutes;
private float mHour;
private boolean mChanged;
public AnalogClock(Context context) {
this(context, null);
}
public AnalogClock(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
Context mContext;
public AnalogClock(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
Resources r = context.getResources();
mContext=context;
Log.d(AnalogClock.DEBUGTAG,"Analog clock started");
mDial = r.getDrawable(R.drawable.clock4);
mDial_frame = r.getDrawable(R.drawable.clock_frame);
mDial_center = r.getDrawable(R.drawable.clock_dot);
mHourHand = r.getDrawable(R.drawable.hour_hand);
mMinuteHand = r.getDrawable(R.drawable.minute_hand);
mSecondHand = r.getDrawable(R.drawable.second_hand);
mCalendar = new Time();
mDialWidth = mDial.getIntrinsicWidth();
mDialHeight = mDial.getIntrinsicHeight();
}
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (!mAttached) {
mAttached = true;
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_TIME_TICK);
filter.addAction(Intent.ACTION_TIME_CHANGED);
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
getContext().registerReceiver(mIntentReceiver, filter, null, mHandler);
}
// NOTE: It's safe to do these after registering the receiver since the receiver always runs
// in the main thread, therefore the receiver can't run before this method returns.
// The time zone may have changed while the receiver wasn't registered, so update the Time
mCalendar = new Time();
// Make sure we update to the current time
onTimeChanged();
counter.start();
}
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mAttached) {
counter.cancel();
getContext().unregisterReceiver(mIntentReceiver);
mAttached = false;
}
}
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
float hScale = 1.0f;
float vScale = 1.0f;
if (widthMode != MeasureSpec.UNSPECIFIED && widthSize < mDialWidth) {
hScale = (float) widthSize / (float) mDialWidth;
}
if (heightMode != MeasureSpec.UNSPECIFIED && heightSize < mDialHeight) {
vScale = (float )heightSize / (float) mDialHeight;
}
float scale = Math.min(hScale, vScale);
Log.d(AnalogClock.DEBUGTAG,"onMeasure params: " + widthSize + " "
+ heightSize + " " + hScale + " " + vScale + " " + scale);
try {
setMeasuredDimension(resolveSizeAndState((int) (mDialWidth * scale), widthMeasureSpec, 0),
resolveSizeAndState((int) (mDialHeight * scale), heightMeasureSpec, 0));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mChanged = true;
}
boolean mSeconds=false;
float mSecond=0;
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
boolean changed = mChanged;
if (changed) {
mChanged = false;
}
boolean seconds = mSeconds;
if (seconds ) {
mSeconds = false;
}
int availableWidth = this.getMeasuredWidth();
int availableHeight = this.getMeasuredHeight();
int x = availableWidth / 2;
int y = availableHeight / 2;
final Drawable dial = mDial;
final Drawable dial_frame = mDial_frame;
final Drawable dial_dot = mDial_center;
int w = dial.getIntrinsicWidth();
int h = dial.getIntrinsicHeight();
boolean scaled = false;
// Log.d(AnalogClock.DEBUGTAG,"onDraw params: " + availableWidth +" "+ availableHeight + " " +
// x + " " + y + " " + w + " "+ h + " " + changed);
if (availableWidth < w || availableHeight < h) {
scaled = true;
//float scale = Math.min((float) availableWidth / (float) w,
// (float) availableHeight / (float) h);
canvas.save();
float scale1 = (float) 0.6;
float scale2 = (float) 0.8;
// Log.d(AnalogClock.DEBUGTAG,"scale params: " + scale1 + " " + scale2);
canvas.scale(scale1, scale2, x, y);
}
if (changed) {
//Log.d(AnalogClock.DEBUGTAG,"Bounds params: " + (x - (w / 2)) + " " + (y - (h / 2)) + " " + ( x + (w / 2)) + " " + (y + (h / 2)));
dial.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
//dial_frame.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
//Log.d(AnalogClock.DEBUGTAG,"Bounds params: " + (x - (w / 2 + w/10)) + " " + (y - (h / 2 + h/10)) + " " + ( x + (w / 2 + w/10)) + " " +
// (y + (h / 2 + h/10)));
dial_frame.setBounds(x - (w/2 + w/10), y - (h/2 + h/10), x + (w/2 + w/10), y + (h/2 + h/10));
dial_dot.setBounds(x -30 , y -20 , x + 30, y + 20);
//Log.d(AnalogClock.DEBUGTAG,"Bounds params: " + (x ) + " " + (y) + " " + ( x + (w / 2 )) + " " +
// (y + (h / 2)));
}
int radius = 0;
if(x>y)
radius=y-10;
else
radius=x-10;
Paint circlepaint;
circlepaint = new Paint();
circlepaint.
dial.draw(canvas);
dial_frame.draw(canvas);
// canvas.drawCircle(x, y, radius, circlepaint);
canvas.save();
canvas.rotate(mHour / 12.0f * 180.0f, x - 10, y - 10);
final Drawable hourHand = mHourHand;
if (changed) {
w = hourHand.getIntrinsicWidth();
h = hourHand.getIntrinsicHeight();
hourHand.setBounds(x -w/2, y - h/2 - h/4 , x + w/6, y + h/6);
}
hourHand.draw(canvas);
canvas.restore();
canvas.save();
canvas.rotate(mMinutes / 60.0f * 360.0f, x - 10, y - 10);
final Drawable minuteHand = mMinuteHand;
if (changed) {
w = minuteHand.getIntrinsicWidth();
h = minuteHand.getIntrinsicHeight();
//minuteHand.setBounds(x, y, x + (w / 2 + w/10), y + (h / 2 + w/10));
minuteHand.setBounds(x - w, y - h/2, x + w/6, y + h/6);
// Log.d(AnalogClock.DEBUGTAG,"Bounds params:x " + (x) + " y " + (y) + " w " + ( w ) + " h " +
// (h));
// Log.d(AnalogClock.DEBUGTAG,"Bounds params: " + (x - w) + " " + (y - h/2) + " " + ( x ) + " " +
// (y));
}
minuteHand.draw(canvas);
canvas.restore();
canvas.save();
canvas.rotate(mSecond, x, y);
if (seconds) {
w = mSecondHand.getIntrinsicWidth();
h = mSecondHand.getIntrinsicHeight();
// mSecondHand.setBounds(x, y, x + (w / 2 + w/10), y + (h / 2 + w/10));
mSecondHand.setBounds(x-w/6, y-h/6, x + w,y + h/2);
Log.d(AnalogClock.DEBUGTAG,"Bounds params: " + (x ) + " " + (y) + " " + ( w) + " " +
(h));
}
mSecondHand.draw(canvas);
canvas.restore();
canvas.save();
dial_dot.draw(canvas);
if (scaled) {
canvas.restore();
}
}
MyCount counter = new MyCount(10000, 1000);
public class MyCount extends CountDownTimer{
public MyCount(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
#Override
public void onFinish() {
counter.start();
}
#Override
public void onTick(long millisUntilFinished) {
mCalendar.setToNow();
int second = mCalendar.second;
mSecond=6.0f*second;
mSeconds=true;
//mChanged = true;
AnalogClock.this.invalidate();
}
}
private void onTimeChanged() {
mCalendar.setToNow();
int hour = mCalendar.hour;
int minute = mCalendar.minute;
int second = mCalendar.second;
mMinutes = minute + second / 60.0f;
mHour = hour + mMinutes / 60.0f;
mChanged = true;
}
private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED)) {
String tz = intent.getStringExtra("time-zone");
mCalendar = new Time(TimeZone.getTimeZone(tz).getID());
}
onTimeChanged();
invalidate();
}
};
}
Related
I have the current code which draw a bounding box around a user's face on a live camera preview.
I am also trying to draw the position of facial landmarks on the live camera preview. It draws them but not at the right location due to not having the scale value
I found this code online but am struggling to compute this scale value as it is a live camera preview and not a bitmap image
Example code found online
double scale = Math.min( viewWidth / imageWidth, viewHeight / imageHeight );
for (Landmark landmark : face.getLandmarks()) {
int cx = (int) (landmark.getPosition().x * scale);
int cy = (int) (landmark.getPosition().y * scale);
canvas.drawCircle(cx, cy, 10, paint);
}
My Function
#Override
public void draw(Canvas canvas) {
Face face = mFace;
if (face == null) {
return;
}
// Draws a circle at the position of the detected face, with the face's track id below.
float x = translateX(face.getPosition().x + face.getWidth() / 2);
float y = translateY(face.getPosition().y + face.getHeight() / 2);
canvas.drawCircle(x, y, FACE_POSITION_RADIUS, mFacePositionPaint);
// Draws a bounding box around the face.
float xOffset = scaleX(face.getWidth() / 2.0f);
float yOffset = scaleY(face.getHeight() / 2.0f);
float left = x - xOffset;
float top = y - yOffset;
float right = x + xOffset;
float bottom = y + yOffset;
canvas.drawRect(left, top, right, bottom, mBoxPaint);
Paint paint = new Paint();
paint.setColor( Color.GREEN );
paint.setStyle( Paint.Style.STROKE );
paint.setStrokeWidth( 5 );
for ( Landmark landmark : face.getLandmarks() ) {
int cx = (int) ( landmark.getPosition().x);
int cy = (int) ( landmark.getPosition().y);
canvas.drawCircle( cx, cy, 10, paint );
}
}
Solved via the following, but not wholly accurate
if ((contains(face.getLandmarks(), 11) != 99)
&& (contains(face.getLandmarks(), 5) != 99)
&& (contains(face.getLandmarks(), 6) != 99)
) {
Log.i(TAG, "draw: Mouth Open >> found all the points");
/**
* for bottom mouth
*/
int cBottomMouthX;
int cBottomMouthY;
cBottomMouthX = (int) translateX(face.getLandmarks().get(contains(face.getLandmarks(), 0)).getPosition().x);
cBottomMouthY = (int) translateY(face.getLandmarks().get(contains(face.getLandmarks(), 0)).getPosition().y);
Log.i(TAG, "draw: Condition Bottom mouth >> cBottomMouthX >> " + cBottomMouthX + " cBottomMouthY >> " + cBottomMouthY);
canvas.drawCircle(cBottomMouthX, cBottomMouthY, 10, paint);
/**
* for left mouth
*/
int cLeftMouthX;
int cLeftMouthY;
cLeftMouthX = (int) translateX(face.getLandmarks().get(contains(face.getLandmarks(), 5)).getPosition().x);
cLeftMouthY = (int) translateY(face.getLandmarks().get(contains(face.getLandmarks(), 5)).getPosition().y);
Log.i(TAG, "draw: Condition LEft mouth >> cLeftMouthX >> " + cLeftMouthX + " cLeftMouthY >> " + cLeftMouthY);
cLeftMouthX = (int) translateX(face.getLandmarks().get(contains(face.getLandmarks(), 5)).getPosition().x);
cLeftMouthY = (int) translateY(face.getLandmarks().get(contains(face.getLandmarks(), 5)).getPosition().y);
canvas.drawCircle(cLeftMouthX, cLeftMouthY, 10, paint);
/**
* for Right mouth
*/
int cRightMouthX;
int cRightMouthY;
cRightMouthX = (int) translateX(face.getLandmarks().get(contains(face.getLandmarks(), 11)).getPosition().x);
cRightMouthY = (int) translateY(face.getLandmarks().get(contains(face.getLandmarks(), 11)).getPosition().y);
Log.i(TAG, "draw: Condition Right mouth >> cRightMouthX >> " + cRightMouthX + " cRightMouthY >> " + cRightMouthY);
cRightMouthX = (int) translateX(face.getLandmarks().get(contains(face.getLandmarks(), 11)).getPosition().x);
cRightMouthY = (int) translateY(face.getLandmarks().get(contains(face.getLandmarks(), 11)).getPosition().y);
canvas.drawCircle(cRightMouthX, cRightMouthY, 10, paint);
float centerPointX = (cLeftMouthX + cRightMouthX) / 2;
float centerPointY = ((cLeftMouthY + cRightMouthY) / 2) - 20;
canvas.drawCircle(centerPointX, centerPointY, 10, paint);
float differenceX = centerPointX - cBottomMouthX;
float differenceY = centerPointY - cBottomMouthY;
Log.i(TAG, "draw: difference X >> " + differenceX + " Y >> " + differenceY);
if (differenceY < (-60)) {
Log.i(TAG, "draw: difference - Mouth is OPENED ");
} else {
Log.i(TAG, "draw: difference - Mouth is CLOSED ");
}
}
}
private int contains (List < Landmark > list,int name){
for (int i = 0; i < list.size(); i++) {
if (list.get(i).getType() == name) {
return i;
}
}
return 99;
}
i have relative parent layout and adding custom textview dynamically into it. when i drag(move) and scale my current textview it get weird jumps continuously in both pointer index. how can i solve this issue?
my custom textview as given below:
public class VideoTextView extends TextView implements View.OnTouchListener {
private final String TAG = this.getClass().getSimpleName();
private Context context;
private Matrix matrix = new Matrix();
private Matrix savedMatrix = new Matrix();
private PointF start = new PointF();
private PointF mid = new PointF();
private float[] matrixValues = new float[9];
private Paint paint;
private Paint linePaint;
private VideoTextMovement videoTextMovement;
private OperationListener operationListener;
private int widthView, heightView;
private boolean isInEdit;
public VideoTextView(Context context, int widthView, int heightView) {
super(context);
this.context = context;
this.widthView = widthView;
this.heightView = heightView;
videoTextMovement = (VideoTextMovement) context;
init();
}
public void updateViewWidthHeight(int widthView, int heightView) {
this.widthView = widthView;
this.heightView = heightView;
}
private void init() {
paint = new Paint();
paint.setTextSize(8);
paint.setColor(context.getResources().getColor(R.color.white));
linePaint = new Paint();
linePaint.setColor(getResources().getColor(R.color.colorPrimary));
linePaint.setAntiAlias(true);
linePaint.setDither(true);
linePaint.setStyle(Paint.Style.STROKE);
linePaint.setStrokeWidth(3.0f);
// setTextSize(8f);
setTextColor(getResources().getColor(R.color.colorAccent));
setOnTouchListener(this);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int textWidth = getMeasuredWidth();
int textHeight = getMeasuredHeight();
int origWidth = textWidth;
int origHeight = textHeight;
matrix.getValues(matrixValues);
canvas.save();
canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG & Paint.FILTER_BITMAP_FLAG));
float transX = matrixValues[Matrix.MTRANS_X];
float transY = matrixValues[Matrix.MTRANS_Y];
float scaleX = matrixValues[Matrix.MSCALE_X];
float scaleY = matrixValues[Matrix.MSCALE_Y];
float maxScale = widthView / textWidth;
Log.e(TAG + " ====", "matrix scale " + scaleX + " " + scaleY + " max scale " + maxScale);
scaleX = Math.max(0.5f, Math.min(scaleX, maxScale));
scaleY = Math.max(0.5f, Math.min(scaleY, maxScale));
if (scaleX > 1.0f) {
textWidth = (int) (textWidth + (textWidth * (scaleX - 1.0f)));
} else if (scaleX < 1.0f) {
textWidth = (int) (textWidth * scaleX);
}
if (scaleY > 1.0f) {
textHeight = (int) (textHeight + (textHeight * (scaleY - 1.0f)));
} else if (scaleY < 1.0f) {
textHeight = (int) (textHeight * scaleY);
}
Log.e(TAG + " ====", "original Tx-Ty " + transX + " - " + transY);
if (transX < 0) {
transX = 0;
}
if (transY < 0) {
transY = 0;
}
if (transX > (widthView - textWidth)) {
transX = widthView - textWidth;
}
if (transY > (heightView - textHeight)) {
transY = heightView - textHeight;
}
Log.e(TAG + " ====", "original w-h " + origWidth + " - " + origHeight + " " + " increased w-h " + textWidth + " - " + textHeight);
Log.e(TAG + " ====", "diff w-h " + Math.abs(origWidth - textWidth) + " - " + Math.abs(origHeight - textHeight));
matrixValues[Matrix.MTRANS_X] = transX;
matrixValues[Matrix.MTRANS_Y] = transY;
matrixValues[Matrix.MSCALE_X] = scaleX;
matrixValues[Matrix.MSCALE_Y] = scaleY;
matrix.setValues(matrixValues);
setX(transX + (textWidth - origWidth) / 2);
setY(transY + (textHeight - origHeight) / 2);
setScaleX(scaleX);
setScaleY(scaleY);
// setPivotX(mid.x);
// setPivotY(mid.y);
Log.e(TAG + " ====", "translateFactor " + transX + " - " + transY + " scaleFactor " + scaleX + " - " + scaleY);
videoTextMovement.translateText(getId(), transX, transY, textWidth, textHeight, getTextSize());
if (isInEdit) {
canvas.drawLine(0, origHeight, origWidth, origHeight, linePaint);
}
canvas.restore();
Log.e(TAG + " ===", TAG + " onDraw");
}
public void midPoint(MotionEvent event) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
Log.e(TAG + " ====", "mid point x-y " + (x / 2) + " " + (y / 2));
mid.set(x / 2, y / 2);
}
private float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
Log.e(TAG + " ====", "spacing x-y " + (x * x + y * y));
return (float) Math.sqrt(x * x + y * y);
}
float rawX0;
float rawY0;
float rawX1;
float rawY1;
private void getOriginalLocation(MotionEvent event) {
int[] location = {0, 0};
getLocationOnScreen(location);
rawX0 = event.getX(0) + location[0];
rawY0 = event.getY(0) + location[1];
float x = event.getRawX();
float y = event.getRawY();
Log.e(TAG + " ===", "actual raw co. " + x + "-" + y);
Log.e(TAG + " ===", "custom raw co. " + rawX0 + "-" + rawY0);
rawX1 = event.getX(1) + location[0];
rawY1 = event.getY(1) + location[1];
}
private float getRawX(MotionEvent event, int pointerIndex) {
float offset = event.getRawX() - event.getX();
return event.getX(pointerIndex) + offset;
}
private float getRawY(MotionEvent event, int pointerIndex) {
float offset = event.getRawY() - event.getY();
return event.getY(pointerIndex) + offset;
}
public void setInEdit(boolean isInEdit) {
this.isInEdit = isInEdit;
invalidate();
}
public void setOperationListener(OperationListener operationListener) {
this.operationListener = operationListener;
}
private float oldDist;
private final int NONE = -1;
private final int DRAG = 1;
private final int ZOOM = 2;
private int mode = NONE;
#Override
public boolean onTouch(View view, MotionEvent event) {
float downX, downY;
float moveX, moveY;
switch (event.getAction() & event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
downX = event.getX();
downY = event.getY();
savedMatrix.set(matrix);
start.set(downX, downY);
mode = DRAG;
Log.e(TAG + " ===", "Action down X=" + downX + " Y=" + downY);
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
savedMatrix.set(matrix);
midPoint(event);
mode = ZOOM;
Log.e(TAG + " ===", "Pointer down");
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
moveX = event.getX();
moveY = event.getY();
float mdX = moveX - start.x;
float mdY = moveY - start.y;
matrix.set(savedMatrix);
matrix.postTranslate(mdX, mdY);
invalidate();
Log.e(TAG + " ===", "draging");
Log.e(TAG + " ===", "draging x-y rawx-rawy " + event.getX() + "-" + event.getY() + " " + event.getRawX() + "-" + event.getRawY());
} else if (mode == ZOOM) {
float newDist = spacing(event);
float scale = (newDist / oldDist);
matrix.set(savedMatrix);
Log.e(TAG + " ====", "Zoom scale " + scale);
matrix.postScale(scale, scale/*, mid.x, mid.y*/);
invalidate();
Log.e(TAG + " ===", "scaling");
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
Log.e(TAG + " ===", "Action up, Pointer up");
break;
}
if (operationListener != null) {
operationListener.onEdit(this);
}
return true;
}
public interface OperationListener {
void onEdit(VideoTextView videoTextview);
}
}
I have added my touch listener and all necessary functions that i have used to perform drag and scale event in my code to solve this issue, but every time i get fail to solve.
My Layout XML:
<FrameLayout
android:id="#+id/videoEditorParent"
android:layout_width="match_parent"
android:layout_height="400dp">
<RelativeLayout
android:id="#+id/vidEditorWrapper"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="#color/colorAccent">
<VideoView
android:id="#+id/vidEditor"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
</FrameLayout>
can somebody help to solve this kind to problem?
Thanks.
I want to add a rectangular border on my ImageView which allow users to change it's size from 8 directions to provide them a preview for cropping purpose.
Which way I can implement to achieve my purpose best, defining a custom ImageView and add code to draw rectangle or add ImageView to a SurfaceView?
Here is my code which I can use to draw a rectangle around my image:
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.DragEvent;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
public class CustomCropImageView extends ImageView implements View.OnTouchListener{
// Bitmap to draw.
Bitmap myBitmap;
// Fundamental attributes.
int xPos, yPos;
int originWidth, originHeight;
int widthImg, heightImg;
int xCrop, yCrop;
int cropWidth, cropHeight;
GestureDetector myGesture;
public CustomCropImageView(Context context){
super(context);
xPos = yPos = xCrop = yCrop = 0;
// setOnTouchListener(this);
}
public CustomCropImageView(Context context, AttributeSet attSet){
super(context, attSet);
xPos = yPos = xCrop = yCrop = 0;
// setOnTouchListener(this);
}
#Override
protected void onDraw(Canvas canvas) {
Drawable drawable = getDrawable();
if(drawable == null)
return;
if(originWidth == 0 && originHeight == 0){
Bitmap tmp = ((BitmapDrawable)drawable).getBitmap();
myBitmap = tmp.copy(Bitmap.Config.ARGB_8888, true);
originWidth = myBitmap.getWidth();
originHeight = myBitmap.getHeight();
Integer[] myDWAndH = getScreenWidthAndHeight();
widthImg = cropWidth = myDWAndH[0];
heightImg = cropHeight = (int)((float)myDWAndH[0]*((float)originHeight / (float)originWidth));
yPos = yCrop = (myDWAndH[1] - heightImg) / 2;
myBitmap = Bitmap.createScaledBitmap(myBitmap, widthImg, heightImg, false);
}
Paint myPaint = new Paint();
canvas.drawBitmap(myBitmap, xPos, yPos, myPaint);
drawAnchorRectangle(canvas);
}
void drawAnchorRectangle(Canvas canvas){
// Anchor rectangle.
Paint myPaint = new Paint();
myPaint.setStyle(Paint.Style.STROKE);
myPaint.setColor(getContext().getResources().getColor(R.color.ImgVBorder));
myPaint.setStrokeWidth(5);
Rect myRect = new Rect(xCrop, yCrop, cropWidth, yCrop + cropHeight);
canvas.drawRect(myRect, myPaint);
// Anchor point.
myPaint.setStyle(Paint.Style.FILL);
myPaint.setColor(getContext().getResources().getColor(R.color.ImgVAnchorPoint));
myPaint.setStrokeWidth(3);
int anchorPointW = 10;
int halfAnchorPointW = anchorPointW / 2;
/*
// Top left.
Rect anchorPoint = new Rect(xCrop + cropWidth - halfAnchorPointW, yCrop - halfAnchorPointW,
anchorPointW, yCrop + halfAnchorPointW);
canvas.drawRect(anchorPoint, myPaint);
// Top right.
anchorPoint.set(xCrop + cropWidth - halfAnchorPointW, yCrop - halfAnchorPointW,
anchorPointW, yCrop + halfAnchorPointW);
canvas.drawRect(anchorPoint, myPaint);
*/
}
Integer[] getScreenWidthAndHeight(){
DisplayMetrics dMetrics = new DisplayMetrics();
((MainActivity)getContext()).getWindowManager().getDefaultDisplay().getMetrics(dMetrics);
Integer[] myResult = new Integer[2];
myResult[0] = dMetrics.widthPixels - 40;
myResult[1] = dMetrics.heightPixels;
return myResult;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getActionMasked();
final String TAG = "!!!123";
switch (action) {
case MotionEvent.ACTION_DOWN:
Log.d(TAG, "Action was DOWN");
return true;
case MotionEvent.ACTION_MOVE:
Log.d(TAG, "Action was MOVE");
break;
case MotionEvent.ACTION_UP:
Log.d(TAG, "Action was UP");
break;
case MotionEvent.ACTION_CANCEL:
Log.d(TAG, "Action was CANCEL");
break;
case MotionEvent.ACTION_OUTSIDE:
Log.d(TAG, "Movement occurred outside bounds of current screen element");
break;
}
return super.onTouchEvent(event);
}
#Override
public boolean onTouch(View v, MotionEvent event) {
return super.onTouchEvent(event);
}
}
Here's how i solved, by defining a custom image view and make some change in OnDraw method, i also added code to reduce brightness of image so it looks nice with a background image behind the real when you resize the rectangle:
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.DragEvent;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import java.util.ArrayList;
import java.util.List;
public class CustomCropImageView extends ImageView implements View.OnTouchListener{
// Bitmap to draw.
Bitmap myBitmap;
// Fundamental attributes.
int xPos, yPos;
int originWidth, originHeight;
int widthImg, heightImg;
int xCrop, yCrop;
int cropWidth, cropHeight;
int offsetLeft = 0, offsetRight = 0, offsetTop = 0, offsetBottom = 0;
// List of anchor point rectangle.
List<Rect> anchorPoints;
int anchorPointW = 30;
int halfAnchorPointW = anchorPointW / 2;
// Background bitmap for cropping.
Bitmap darkBitmap;
public CustomCropImageView(Context context){
super(context);
xPos = yPos = xCrop = yCrop = 0;
// setOnTouchListener(this);
}
public CustomCropImageView(Context context, AttributeSet attSet){
super(context, attSet);
xPos = yPos = xCrop = yCrop = 0;
// setOnTouchListener(this);
}
Integer[] myDWAndH;
#Override
protected void onDraw(Canvas canvas) {
Drawable drawable = getDrawable();
if(drawable == null)
return;
if(originWidth == 0 && originHeight == 0){
Bitmap tmp = ((BitmapDrawable)drawable).getBitmap();
myBitmap = tmp.copy(Bitmap.Config.ARGB_8888, true);
originWidth = myBitmap.getWidth();
originHeight = myBitmap.getHeight();
myDWAndH = getScreenWidthAndHeight();
widthImg = cropWidth = myDWAndH[0] - anchorPointW;
heightImg = cropHeight = (int)((float)myDWAndH[0]*((float)originHeight / (float)originWidth)) - anchorPointW;
yPos = yCrop = (myDWAndH[1] - heightImg) / 2;
myBitmap = Bitmap.createScaledBitmap(myBitmap, widthImg, heightImg, false);
createDarkBitmap(myBitmap);
initAnchorPoint();
}
Paint myPaint = new Paint();
canvas.drawBitmap(darkBitmap, xPos + halfAnchorPointW, yPos + halfAnchorPointW, myPaint);
drawAnchorRectangle(canvas);
}
void drawAnchorRectangle(Canvas canvas){
// Anchor rectangle.
Paint myPaint = new Paint();
canvas.drawBitmap(myBitmap, new Rect(offsetLeft, offsetTop, cropWidth + offsetRight, cropHeight + offsetBottom),
new Rect(xCrop + halfAnchorPointW + offsetLeft, yCrop + halfAnchorPointW + offsetTop,
xCrop + halfAnchorPointW + cropWidth + offsetRight, yCrop + halfAnchorPointW + cropHeight + offsetBottom), myPaint);
myPaint.setStyle(Paint.Style.STROKE);
myPaint.setColor(getContext().getResources().getColor(R.color.ImgVBorder));
myPaint.setStrokeWidth(5);
Rect myRect = new Rect(xCrop + halfAnchorPointW + offsetLeft, yCrop + halfAnchorPointW + offsetTop,
xCrop + halfAnchorPointW + cropWidth + offsetRight, yCrop + halfAnchorPointW + cropHeight + offsetBottom);
canvas.drawRect(myRect, myPaint);
// Anchor point.
myPaint.setStyle(Paint.Style.FILL);
myPaint.setColor(getContext().getResources().getColor(R.color.ImgVAnchorPoint));
// Top left.
canvas.drawRect(anchorPoints.get(0), myPaint);
// Top right.
canvas.drawRect(anchorPoints.get(1), myPaint);
// Bottom left.
canvas.drawRect(anchorPoints.get(2), myPaint);
// Bottom right.
canvas.drawRect(anchorPoints.get(3), myPaint);
}
void initAnchorPoint(){
if(anchorPoints != null)
anchorPoints.clear();
else
anchorPoints = new ArrayList<>();
// Top left.
anchorPoints.add(new Rect(xCrop + offsetLeft, yCrop + offsetTop,
xCrop + anchorPointW + offsetLeft, yCrop + anchorPointW + offsetTop));
// Top right.
anchorPoints.add(new Rect(xCrop + cropWidth + offsetRight, yCrop + offsetTop,
xCrop + cropWidth + anchorPointW + offsetRight, yCrop + anchorPointW + offsetTop));
// Bottom left.
anchorPoints.add(new Rect(xCrop + offsetLeft, yCrop + cropHeight + offsetBottom,
xCrop + anchorPointW + offsetLeft, yCrop + cropHeight + anchorPointW + offsetBottom));
// Bottom right.
anchorPoints.add(new Rect(xCrop + cropWidth + offsetRight, yCrop + cropHeight + offsetBottom,
xCrop + cropWidth + anchorPointW + offsetRight, yCrop + cropHeight + anchorPointW + offsetBottom));
}
Integer[] getScreenWidthAndHeight(){
DisplayMetrics dMetrics = new DisplayMetrics();
((MainActivity)getContext()).getWindowManager().getDefaultDisplay().getMetrics(dMetrics);
Integer[] myResult = new Integer[2];
myResult[0] = dMetrics.widthPixels - 40;
myResult[1] = dMetrics.heightPixels;
return myResult;
}
int anchorChoice = -1;
void setAnchorAction(MotionEvent event){
int x = (int)event.getRawX();
int y = (int)event.getRawY();
int offset = 50 + anchorPointW;
anchorChoice = -1;
if(y > (anchorPoints.get(0).top - offset) && y < (anchorPoints.get(0).bottom + offset)){
if(x < (anchorPoints.get(0).right + offset) && x > (anchorPoints.get(0).left - offset)){
anchorChoice = 0;
}
else if(x < (anchorPoints.get(1).right + offset) && x > (anchorPoints.get(1).left - offset))
anchorChoice = 1;
}
else if(y > (anchorPoints.get(2).top - offset) && y < (anchorPoints.get(2).bottom + offset)){
if(x < (anchorPoints.get(2).right + offset) && x > (anchorPoints.get(2).left - offset)){
anchorChoice = 2;
}
else if(x < (anchorPoints.get(3).right + offset) && x > (anchorPoints.get(3).left - offset))
anchorChoice = 3;
}
}
void resizeRectangle(MotionEvent event){
if(anchorChoice == -1)
return;
int x = (int)event.getRawX();
int y = (int)event.getRawY();
int dif = 0;
initAnchorPoint();
invalidate();
// xCrop + halfAnchorPointW + offsetLeft, yCrop + halfAnchorPointW + offsetTop,
// xCrop + halfAnchorPointW + cropWidth + offsetRight, yCrop + halfAnchorPointW + cropHeight + offsetBottom
int prevOLeft = offsetLeft;
int prevORight = offsetRight;
int prevOTop = offsetTop;
int prevOBottom = offsetBottom;
if(anchorChoice == 0){
offsetLeft = (x - xCrop - halfAnchorPointW);
offsetTop = (y - yCrop - halfAnchorPointW);
}
else if(anchorChoice == 1){
offsetRight = (x - xCrop - halfAnchorPointW - cropWidth);
offsetTop = (y - yCrop - halfAnchorPointW);
}
else if(anchorChoice == 2){
offsetLeft = (x - xCrop - halfAnchorPointW);
offsetBottom = (y - yCrop - halfAnchorPointW - cropHeight);
}
else if(anchorChoice == 3){
offsetRight = (x - xCrop - halfAnchorPointW - cropWidth);
offsetBottom = (y - yCrop - halfAnchorPointW - cropHeight);
}
// Boundaries.
// Left boundary.
if(xCrop + offsetLeft < xCrop)
offsetLeft = 0;
if(xCrop + halfAnchorPointW + cropWidth + offsetRight < xCrop + anchorPointW + offsetLeft)
offsetRight = prevORight;
// Top boundary.
if(yCrop + offsetTop < yCrop)
offsetTop = 0;
if(yCrop + halfAnchorPointW + cropHeight + offsetBottom < yCrop + anchorPointW + offsetTop)
offsetBottom = prevOBottom;
// Right boundary.
if(xCrop + halfAnchorPointW + cropWidth + offsetRight > xCrop + halfAnchorPointW + cropWidth)
offsetRight = 0;
if(xCrop + anchorPointW + offsetLeft > xCrop + halfAnchorPointW + cropWidth + offsetRight)
offsetLeft = prevOLeft;
// Bottom boundary.
if(yCrop + halfAnchorPointW + cropHeight + offsetBottom > yCrop + halfAnchorPointW + cropHeight)
offsetBottom = 0;
if(yCrop + anchorPointW + offsetTop > yCrop + halfAnchorPointW + cropHeight + offsetBottom)
offsetTop = prevOTop;
// End boundaries.
return;
}
void createDarkBitmap(Bitmap processedBitmap){
darkBitmap = Bitmap.createBitmap(processedBitmap.getWidth(), processedBitmap.getHeight(), Bitmap.Config.ARGB_8888);
int substractValue = 220;
for(int i = 0; i < processedBitmap.getWidth(); i++){
for(int j = 0; j < processedBitmap.getHeight(); j++){
int pixelToProcess = processedBitmap.getPixel(i, j);
// Get component infos.
int r = Color.red(pixelToProcess);
int g = Color.green(pixelToProcess);
int b = Color.blue(pixelToProcess);
int alpha = Color.alpha(pixelToProcess);
// Process component info.
alpha -= substractValue;
// alpha = alpha - substractValue;
darkBitmap.setPixel(i, j, Color.argb(alpha, r, g, b));
}
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getActionMasked();
final String TAG = "!!!123";
switch (action) {
case MotionEvent.ACTION_DOWN:
setAnchorAction(event);
Log.d(TAG, "" + anchorChoice);
return true;
case MotionEvent.ACTION_MOVE:
resizeRectangle(event);
break;
case MotionEvent.ACTION_UP:
Log.d(TAG, "Action was UP");
break;
case MotionEvent.ACTION_CANCEL:
Log.d(TAG, "Action was CANCEL");
break;
case MotionEvent.ACTION_OUTSIDE:
Log.d(TAG, "Movement occurred outside bounds of current screen element");
break;
}
return super.onTouchEvent(event);
}
#Override
public boolean onTouch(View v, MotionEvent event) {
return super.onTouchEvent(event);
}
}
first this is my textureView class
public abstract class ScalableTextureView extends TextureView{
private static final boolean SHOW_LOGS = false;
private static final String TAG = ScalableTextureView.class.getSimpleName();
private Integer mContentWidth;
private Integer mContentHeight;
private float mPivotPointX = 0f;
private float mPivotPointY = 0f;
private float mContentScaleX = 1f;
private float mContentScaleY = 1f;
private float mContentRotation = 0f;
private float mContentScaleMultiplier = 1f;
private int mContentX = 0;
private int mContentY = 0;
private final Matrix mTransformMatrix = new Matrix();
private ScaleType mScaleType;
public enum ScaleType {
CENTER_CROP, TOP, BOTTOM, FILL,FITX
}
public ScalableTextureView(Context context) {
super(context);
}
public ScalableTextureView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ScalableTextureView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public ScalableTextureView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public void setScaleType(ScaleType scaleType) {
mScaleType = scaleType;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (SHOW_LOGS) Logger.v(TAG, "onMeasure, mContentoWidth " + mContentWidth + ", mContentHeight " + mContentHeight);
if (mContentWidth != null && mContentHeight != null) {
updateTextureViewSize();
}
}
public void updateTextureViewSize() {
if (SHOW_LOGS) Logger.d(TAG, ">> updateTextureViewSize");
if (mContentWidth == null || mContentHeight == null) {
throw new RuntimeException("null content size");
}
float viewWidth = getMeasuredWidth();
float viewHeight = getMeasuredHeight();
float contentWidth = mContentWidth;
float contentHeight = mContentHeight;
if (SHOW_LOGS) {
Logger.v(TAG, "updateTextureViewSize, mContentWidth " + mContentWidth + ", mContentHeight " + mContentHeight + ", mScaleType " + mScaleType);
Logger.v(TAG, "updateTextureViewSize, viewWidth " + viewWidth + ", viewHeight " + viewHeight);
}
float scaleX = 1.0f;
float scaleY = 1.0f;
switch (mScaleType) {
case FILL:
if (viewWidth > viewHeight) { // device in landscape
scaleX = (viewHeight * contentWidth) / (viewWidth * contentHeight);
} else {
scaleY = (viewWidth * contentHeight) / (viewHeight * contentWidth);
}
break;
case BOTTOM:
case CENTER_CROP:
case FITX:
case TOP:
if (contentWidth > viewWidth && contentHeight > viewHeight) {
scaleX = contentWidth / viewWidth;
scaleY = contentHeight / viewHeight;
} else if (contentWidth < viewWidth && contentHeight < viewHeight) {
scaleY = viewWidth / contentWidth;
scaleX = viewHeight / contentHeight;
} else if (viewWidth > contentWidth) {
scaleY = (viewWidth / contentWidth) / (viewHeight / contentHeight);
} else if (viewHeight > contentHeight) {
scaleX = (viewHeight / contentHeight) / (viewWidth / contentWidth);
}
break;
}
if (SHOW_LOGS) {
Logger.v(TAG, "updateTextureViewSize, scaleX " + scaleX + ", scaleY " + scaleY);
}
// Calculate pivot points, in our case crop from center
float pivotPointX;
float pivotPointY;
switch (mScaleType) {
case TOP:
pivotPointX = 0;
pivotPointY = 0;
break;
case BOTTOM:
pivotPointX = viewWidth;
pivotPointY = viewHeight;
break;
case CENTER_CROP:
pivotPointX = viewWidth / 2;
pivotPointY = viewHeight / 2;
break;
case FITX:
pivotPointX = viewWidth ;
pivotPointY = viewHeight ;
break;
case FILL:
pivotPointX = mPivotPointX;
pivotPointY = mPivotPointY;
break;
default:
throw new IllegalStateException("pivotPointX, pivotPointY for ScaleType " + mScaleType + " are not defined");
}
if (SHOW_LOGS)
Logger.v(TAG, "updateTextureViewSize, pivotPointX " + pivotPointX + ", pivotPointY " + pivotPointY);
float fitCoef = 1;
switch (mScaleType) {
case FILL:
break;
case BOTTOM:
case CENTER_CROP:
case TOP:
if (mContentHeight > mContentWidth) { //Portrait video
fitCoef = viewWidth / (viewWidth * scaleX);
} else { //Landscape video
fitCoef = viewHeight / (viewHeight * scaleY);
}
break;
}
mContentScaleX = fitCoef * scaleX;
mContentScaleY = fitCoef * scaleY;
mPivotPointX = pivotPointX;
mPivotPointY = pivotPointY;
updateMatrixScaleRotate();
if (SHOW_LOGS) Logger.d(TAG, "<< updateTextureViewSize");
}
private void updateMatrixScaleRotate() {
if (SHOW_LOGS) Logger.d(TAG, ">> updateMatrixScaleRotate, mContentRotation " + mContentRotation + ", mContentScaleMultiplier " + mContentScaleMultiplier + ", mPivotPointX " + mPivotPointX + ", mPivotPointY " + mPivotPointY);
mTransformMatrix.reset();
mTransformMatrix.setScale(mContentScaleX * mContentScaleMultiplier, mContentScaleY * mContentScaleMultiplier, mPivotPointX, mPivotPointY);
mTransformMatrix.postRotate(mContentRotation, mPivotPointX, mPivotPointY);
setTransform(mTransformMatrix);
if (SHOW_LOGS) Logger.d(TAG, "<< updateMatrixScaleRotate, mContentRotation " + mContentRotation + ", mContentScaleMultiplier " + mContentScaleMultiplier + ", mPivotPointX " + mPivotPointX + ", mPivotPointY " + mPivotPointY);
}
private void updateMatrixTranslate() {
if (SHOW_LOGS) {
Logger.d(TAG, "updateMatrixTranslate, mContentX " + mContentX + ", mContentY " + mContentY);
}
float scaleX = mContentScaleX * mContentScaleMultiplier;
float scaleY = mContentScaleY * mContentScaleMultiplier;
mTransformMatrix.reset();
mTransformMatrix.setScale(scaleX, scaleY, mPivotPointX, mPivotPointY);
mTransformMatrix.postTranslate(mContentX, mContentY);
setTransform(mTransformMatrix);
}
#Override
public void setRotation(float degrees) {
if (SHOW_LOGS)
Logger.d(TAG, "setRotation, degrees " + degrees + ", mPivotPointX " + mPivotPointX + ", mPivotPointY " + mPivotPointY);
mContentRotation = degrees;
updateMatrixScaleRotate();
}
#Override
public float getRotation() {
return mContentRotation;
}
#Override
public void setPivotX(float pivotX) {
if (SHOW_LOGS) Logger.d(TAG, "setPivotX, pivotX " + pivotX);
mPivotPointX = pivotX;
}
#Override
public void setPivotY(float pivotY) {
if (SHOW_LOGS) Logger.d(TAG, "setPivotY, pivotY " + pivotY);
mPivotPointY = pivotY;
}
#Override
public float getPivotX() {
return mPivotPointX;
}
#Override
public float getPivotY() {
return mPivotPointY;
}
public float getContentAspectRatio() {
return mContentWidth != null && mContentHeight != null
? (float) mContentWidth / (float) mContentHeight
: 0;
}
/**
* Use it to animate TextureView content x position
* #param x
*/
public final void setContentX(float x) {
mContentX = (int) x - (getMeasuredWidth() - getScaledContentWidth()) / 2;
updateMatrixTranslate();
}
/**
* Use it to animate TextureView content x position
* #param y
*/
public final void setContentY(float y) {
mContentY = (int) y - (getMeasuredHeight() - getScaledContentHeight()) / 2;
updateMatrixTranslate();
}
protected final float getContentX() {
return mContentX;
}
protected final float getContentY() {
return mContentY;
}
/**
* Use it to set content of a TextureView in the center of TextureView
*/
public void centralizeContent() {
int measuredWidth = getMeasuredWidth();
int measuredHeight = getMeasuredHeight();
int scaledContentWidth = getScaledContentWidth();
int scaledContentHeight = getScaledContentHeight();
if (SHOW_LOGS) Logger.d(TAG, "centralizeContent, measuredWidth " + measuredWidth + ", measuredHeight " + measuredHeight + ", scaledContentWidth " + scaledContentWidth + ", scaledContentHeight " + scaledContentHeight);
mContentX = 0;
mContentY = 0;
if (SHOW_LOGS) Logger.d(TAG, "centerVideo, mContentX " + mContentX + ", mContentY " + mContentY);
updateMatrixScaleRotate();
}
public Integer getScaledContentWidth() {
return (int) (mContentScaleX * mContentScaleMultiplier * getMeasuredWidth());
}
public Integer getScaledContentHeight() {
return (int) (mContentScaleY * mContentScaleMultiplier * getMeasuredHeight());
}
public float getContentScale() {
return mContentScaleMultiplier;
}
public void setContentScale(float contentScale) {
if (SHOW_LOGS) Logger.d(TAG, "setContentScale, contentScale " + contentScale);
mContentScaleMultiplier = contentScale;
updateMatrixScaleRotate();
}
protected final void setContentHeight(int height) {
mContentHeight = height;
}
protected final Integer getContentHeight() {
return mContentHeight;
}
protected final void setContentWidth(int width) {
mContentWidth = width;
}
protected final Integer getContentWidth() {
return mContentWidth;
}
}
now all the scale type fill , top , bottom ... not shown all video size its crop part from Video when i play it i just try to add scale type FITX for show all video no cropping
i try this for crop in Fit X
case FITX:
double aspectRatio = (double) viewHeight / viewWidth;
float newWidth, newHeight;
if (viewHeight > (int) (viewWidth* aspectRatio)) {
newWidth = viewWidth;
newHeight = (int) (viewWidth* aspectRatio);
} else {
// limited by short height; restrict width
newWidth = (int) (viewHeight/ aspectRatio);
newHeight = viewHeight;
}
pivotPointX = newWidth ;
pivotPointY = newHeight ;
break;
but its like scale BOTTOM or TOP i don't know how to solve it complicated to me
NOTE ** FITX added by me in code
I am creating a custom analog clock with images for hour, second, minute hands. The clock works fine but only problem is the anchoring of the hands. Below is an image of the clock attached. The hour, minute hands are anchored at the center which makes the clock look bad. All the hands should be anchored at the edges so that it looks more realistic and readable. Can someone suggest something. My custom view is attached here.
package com.example.submission_customclock;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.BroadcastReceiver;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.CountDownTimer;
import android.os.Handler;
import android.text.format.Time;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.RemoteViews.RemoteView;
import java.util.TimeZone;
/**
* This widget display an analogic clock with two hands for hours and
* minutes.
*
* #attr ref android.R.styleable#AnalogClock_dial
* #attr ref android.R.styleable#AnalogClock_hand_hour
* #attr ref android.R.styleable#AnalogClock_hand_minute
*/
#RemoteView
public class AnalogClock extends View {
private Time mCalendar;
private static final String DEBUGTAG = "FA";
private Drawable mHourHand;
private Drawable mMinuteHand;
private Drawable mSecondHand;
private Drawable mDial;
private Drawable mDial_frame;
private int mDialWidth;
private int mDialHeight;
private boolean mAttached;
private final Handler mHandler = new Handler();
private float mMinutes;
private float mHour;
private boolean mChanged;
public AnalogClock(Context context) {
this(context, null);
}
public AnalogClock(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
Context mContext;
public AnalogClock(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
Resources r = context.getResources();
mContext=context;
Log.d(AnalogClock.DEBUGTAG,"Analog clock started");
mDial = r.getDrawable(R.drawable.clock4);
mDial_frame = r.getDrawable(R.drawable.clock_frame);
mHourHand = r.getDrawable(R.drawable.hour_hand);
mMinuteHand = r.getDrawable(R.drawable.minute_hand);
mSecondHand = r.getDrawable(R.drawable.second_hand);
mCalendar = new Time();
mDialWidth = mDial.getIntrinsicWidth();
mDialHeight = mDial.getIntrinsicHeight();
}
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (!mAttached) {
mAttached = true;
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_TIME_TICK);
filter.addAction(Intent.ACTION_TIME_CHANGED);
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
getContext().registerReceiver(mIntentReceiver, filter, null, mHandler);
}
// NOTE: It's safe to do these after registering the receiver since the receiver always runs
// in the main thread, therefore the receiver can't run before this method returns.
// The time zone may have changed while the receiver wasn't registered, so update the Time
mCalendar = new Time();
// Make sure we update to the current time
onTimeChanged();
counter.start();
}
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mAttached) {
counter.cancel();
getContext().unregisterReceiver(mIntentReceiver);
mAttached = false;
}
}
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
float hScale = 1.0f;
float vScale = 1.0f;
if (widthMode != MeasureSpec.UNSPECIFIED && widthSize < mDialWidth) {
hScale = (float) widthSize / (float) mDialWidth;
}
if (heightMode != MeasureSpec.UNSPECIFIED && heightSize < mDialHeight) {
vScale = (float )heightSize / (float) mDialHeight;
}
float scale = Math.min(hScale, vScale);
Log.d(AnalogClock.DEBUGTAG,"onMeasure params: " + widthSize + " "
+ heightSize + " " + hScale + " " + vScale + " " + scale);
try {
setMeasuredDimension(resolveSizeAndState((int) (mDialWidth * scale), widthMeasureSpec, 0),
resolveSizeAndState((int) (mDialHeight * scale), heightMeasureSpec, 0));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mChanged = true;
}
boolean mSeconds=false;
float mSecond=0;
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
boolean changed = mChanged;
if (changed) {
mChanged = false;
}
boolean seconds = mSeconds;
if (seconds ) {
mSeconds = false;
}
int availableWidth = this.getMeasuredWidth();
int availableHeight = this.getMeasuredHeight();
int x = availableWidth / 2;
int y = availableHeight / 2;
final Drawable dial = mDial;
final Drawable dial_frame = mDial_frame;
int w = dial.getIntrinsicWidth();
int h = dial.getIntrinsicHeight();
boolean scaled = false;
// Log.d(AnalogClock.DEBUGTAG,"onDraw params: " + availableWidth +" "+ availableHeight + " " +
// x + " " + y + " " + w + " "+ h + " " + changed);
if (availableWidth < w || availableHeight < h) {
scaled = true;
//float scale = Math.min((float) availableWidth / (float) w,
// (float) availableHeight / (float) h);
canvas.save();
float scale1 = (float) 0.6;
float scale2 = (float) 0.8;
// Log.d(AnalogClock.DEBUGTAG,"scale params: " + scale1 + " " + scale2);
canvas.scale(scale1, scale2, x, y);
}
if (changed) {
//Log.d(AnalogClock.DEBUGTAG,"Bounds params: " + (x - (w / 2)) + " " + (y - (h / 2)) + " " + ( x + (w / 2)) + " " + (y + (h / 2)));
dial.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
//dial_frame.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
//Log.d(AnalogClock.DEBUGTAG,"Bounds params: " + (x - (w / 2 + w/10)) + " " + (y - (h / 2 + h/10)) + " " + ( x + (w / 2 + w/10)) + " " +
// (y + (h / 2 + h/10)));
dial_frame.setBounds(x - (w/2 + w/10), y - (h/2 + h/10), x + (w/2 + w/10), y + (h/2 + h/10));
}
dial.draw(canvas);
dial_frame.draw(canvas);
canvas.save();
canvas.rotate(mHour / 12.0f * 180.0f, x, y);
final Drawable hourHand = mHourHand;
if (changed) {
w = hourHand.getIntrinsicWidth();
h = hourHand.getIntrinsicHeight();
hourHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
}
hourHand.draw(canvas);
canvas.restore();
canvas.save();
canvas.rotate(mMinutes / 60.0f * 180.0f, x, y);
final Drawable minuteHand = mMinuteHand;
if (changed) {
w = minuteHand.getIntrinsicWidth();
h = minuteHand.getIntrinsicHeight();
minuteHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
}
minuteHand.draw(canvas);
canvas.restore();
canvas.save();
canvas.rotate(mSecond, x, y);
if (seconds) {
w = mSecondHand.getIntrinsicWidth();
h = mSecondHand.getIntrinsicHeight();
mSecondHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
}
mSecondHand.draw(canvas);
canvas.restore();
if (scaled) {
canvas.restore();
}
}
MyCount counter = new MyCount(10000, 1000);
public class MyCount extends CountDownTimer{
public MyCount(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
#Override
public void onFinish() {
counter.start();
}
#Override
public void onTick(long millisUntilFinished) {
mCalendar.setToNow();
int second = mCalendar.second;
mSecond=6.0f*second;
mSeconds=true;
//mChanged = true;
AnalogClock.this.invalidate();
}
}
private void onTimeChanged() {
mCalendar.setToNow();
int hour = mCalendar.hour;
int minute = mCalendar.minute;
int second = mCalendar.second;
mMinutes = minute + second / 60.0f;
mHour = hour + mMinutes / 60.0f;
mChanged = true;
}
private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED)) {
String tz = intent.getStringExtra("time-zone");
mCalendar = new Time(TimeZone.getTimeZone(tz).getID());
}
onTimeChanged();
invalidate();
}
};
}
your problem is with specific dimensions for clock_frame ,minute_hand,hour_hand and second_hand in drawable folder.for example if you take 240 x 240 clockframe the you should takeminute_hand,hour_hand and second_hand as 19 x 240 and these hands should start from top and end with exactly center position of clock_frame with comparition.if u want more fashionable you can end up with slightly distance from exactly center position of clock_frame
Simplest way is to set hands bitmaps the same size as dial and rotate to 12 o clock.