Scale animation of the custom view (relative to the centre point) - java

I have a custom view, which I want to scale relative to the centre.
If I use this line of code for the ImageView it works perfectly well and scale correctly:
imageView.animate().scaleX(2.5f).scaleY(2.5f).setDuration(2000);
But if I use it for my custom view, it goes up, and animation doesn't look correctly, how to fix it?
Here is a video: https://youtu.be/f0-jMqE9ULU
(The animation of the red circle going wrong, animation of the pink circle (imageView) works correctly)
My custom view:
public class CircleDrawView extends View {
private Paint paint;
private int x;
private int y;
private String labelName;
private int radius = 40;
public CircleDrawView(Context context, AttributeSet attrs)
{
super(context, attrs);
}
public CircleDrawView(Context context)
{
super(context);
paint = new Paint();
}
public CircleDrawView(Context context, int x, int y, String labelName)
{
super(context);
paint = new Paint();
this.x=x;
this.y=y;
this.labelName=labelName;
}
#Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
paint.setColor(Color.RED);
canvas.drawCircle(x, y, radius, paint);
Paint textPaint = new Paint();
textPaint.setTextSize(25);
textPaint.setColor(Color.WHITE);
textPaint.setAntiAlias(true);
textPaint.setTextAlign(Paint.Align.CENTER);
Rect bounds = new Rect();
textPaint.getTextBounds(labelName, 0, labelName.length(), bounds);
canvas.drawText(labelName, x, y, textPaint);
}
}
Activity:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LinearLayout rootView =(LinearLayout) findViewById(R.id.test_layout);
ImageView imageView = (ImageView) findViewById(R.id.test_image);
CircleDrawView circle = new CircleDrawView(getApplicationContext(), 200, 200, "1");
rootView.addView(circle);
rootView.invalidate();
circle.animate().scaleX(1.2f).scaleY(1.2f).setDuration(2000);
imageView.animate().scaleX(2.5f).scaleY(2.5f).setDuration(2000);
}
}
xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="com.example.attracti.animation.MainActivity">
<LinearLayout
android:id="#+id/test_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<ImageView
android:id="#+id/test_image"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center_vertical"
android:layout_marginLeft="100dp"
android:background="#drawable/circle_shape" />
</LinearLayout>
</RelativeLayout>

Your call to circle.animate() returns a ViewPropertyAnimator.
The scaleX() and scaleY() methods you call on this ViewPropertyAnimator scale the View about it's pivot.
The pivot of a View is set by the View.setPivotX() and View.setPivotY() methods.
In your constructor, set these values to the supplied x and y. Your view will then scale about the supplied center point.

Related

Draw rect over camera preview

I have a camera preview where i get every frame, for each frame i analyze the objects inside and i have a list that contain every object recognized and the location, so i have already the locations for every single object. Now i want to draw a rect around that object on camera preview, but doing canvas.drawRect doesn't work, any suggestion?
for (final Detector.Recognition result : results) {
final RectF location = result.getLocation();
if (location != null && result.getConfidence() >= 0.1) {
result.setLocation(location);
mappedRecognitions.add(result);
Log.d("OBJECT: ", result.getTitle());
final Paint paint = new Paint();
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(2.0f);
canvas_crop.drawRect(location, paint);
cropToFrameTransform.mapRect(location);
}
}
This is the layout XML
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/black"
android:orientation="vertical">
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
<com.otaliastudios.cameraview.CameraView
android:id="#+id/cameraView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
If you don't need the rectangles to be recorded, so, are only displayed in the live preview, then in general the solution is to overlay a custom view dedicated exclusively to rendering of drawings.
Create a custom view and place it on top, ensuring it always matches the position and size (aspect ratio) of the preview shown by the CameraView. Next an example to get you started, although you will need to add the logic to ensure it matches the CameraView "preview" metrics. Use the setTargets to pass the rectangles to paint:
Java:
public final class OverlayView extends View {
private final Paint paint = new Paint();
private final List<Rect> targets = new ArrayList<>();
public OverlayView(#NonNull final Context context) {
this(context, null);
}
public OverlayView(#NonNull final Context context, #Nullable final AttributeSet attrs) {
this(context, attrs, 0);
}
public OverlayView(#NonNull final Context context, #Nullable final AttributeSet attrs, final int defStyleAttr) {
super(context, attrs, defStyleAttr);
final float density = context.getResources().getDisplayMetrics().density;
this.paint.setStrokeWidth(2.0f * density);
this.paint.setColor(Color.BLUE);
this.paint.setStyle(Paint.Style.STROKE);
}
#Override
protected void onDraw(final Canvas canvas) {
super.onDraw(canvas);
synchronized (this) {
for (final Rect entry : this.targets) {
canvas.drawRect(entry, this.paint);
}
}
}
public void setTargets(#NonNull final List<Rect> sources) {
synchronized (this) {
this.targets.clear();
this.targets.addAll(sources);
this.postInvalidate();
}
}
}
Kotlin:
class OverlayView(context: Context, attrs: AttributeSet) : View(context, attrs) {
private val paint = Paint()
private val targets: MutableList<Rect> = ArrayList()
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
synchronized(this) {
for (entry in targets) {
canvas.drawRect(entry, paint)
}
}
}
fun setTargets(sources: List<Rect>) {
synchronized(this) {
targets.clear()
targets.addAll(sources)
this.postInvalidate()
}
}
init {
val density = context.resources.displayMetrics.density
paint.strokeWidth = 2.0f * density
paint.color = Color.BLUE
paint.style = Paint.Style.STROKE
}
}
And for your specific xml, would be as next:
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/black"
android:orientation="vertical">
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
<com.otaliastudios.cameraview.CameraView
android:id="#+id/cameraView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<com.otaliastudios.cameraview.OverlayView
android:id="#+id/overlayView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Note that you are using match_parent for the CameraView, this should be handled better in code to adjust into all possible camera aspect ratios, and consequently when you resolve the preview size, such must be also applied to the new OverlayView.

How to get smooth circular FrameLayout in Android

I have a menu, each item inside is a Framelayout, which is contain ImageView and TextView inside, the output looks like this screenshot:
RoundedCornerLayout.java is my class which extend FrameLayout to redraw it circular:
public class RoundedCornerLayout extends FrameLayout {
int borderColor;
Paint paint;
private Path path = new Path();
public RoundedCornerLayout(Context context, AttributeSet attrs) {
super(context, attrs);
borderColor = android.graphics.Color.rgb(128,0,129);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(borderColor);
paint.setAntiAlias(true);
paint.setStrokeWidth(8);
paint.setStyle(Paint.Style.STROKE);
paint.setFlags(Paint.ANTI_ALIAS_FLAG);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// compute the path
float halfWidth = w / 2f;
float halfHeight = h / 2f;
float centerX = halfWidth;
float centerY = halfHeight;
path.reset();
path.addCircle(centerX, centerY, Math.min(halfWidth, halfHeight), Path.Direction.CW);
path.close();
}
#Override
protected void dispatchDraw(Canvas canvas) {
int save = canvas.save();
canvas.clipPath(path);
super.dispatchDraw(canvas);
canvas.drawPath(path, paint);
canvas.restoreToCount(save);
}
}
Activity code:
<RoundedCornerLayout
android:id="#+id/viewClicked"
android:layout_width="110dp"
android:layout_height="110dp"
android:layout_marginRight="151dp"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginEnd="8dp"
android:layout_marginLeft="8dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="50dp">
<ImageView
android:id="#+id/imgNature"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="#drawable/pic_nature" />
<TextView
android:id="#+id/lblClick"
android:layout_width="match_parent"
android:layout_height="39dp"
android:layout_marginTop="75dp"
android:background="#CC800081"
android:text="click"
android:textAlignment="center"
android:textColor="#ffffff" />
</RoundedCornerLayout>
what I got here is rounding the FrameLayout including all controls inside, but my problem is that rounding is not smooth as I expected!
Any idea how to edit the above code to get smooth circular FrameLayout ?
Please note that rounding through android:background="#drawable/circularlayout.xml didn't make the rounding over ImageView and TextView without RoundedCornerLayout.java

How do I draw a custom quadratic shape in Android Studio for use as an image placeholder?

I'd like to make a shape similar to this one and use it as an image placeholder. I've learned how to make circles and rectangles using
canvas.drawRect(0,0,500,250,paint);
and from what I've browsed on here I gathered that I need to use paths as illustrated in this page. But I don't know where to begin when I look at the paths page previously linked. How do I create this custom shape, preferably to match the width of the screen? Thanks in advance!
This is my code so far to create a red rectangle that I'll eventually use to insert an image into:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Paint paint = new Paint();
paint.setColor(Color.parseColor("#CD5C5C"));
Bitmap bg = Bitmap.createBitmap(480,800, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bg);
canvas.drawRect(0,0,500,250,paint);
RelativeLayout rl = (RelativeLayout)
findViewById(R.id.activity_main);
rl.setBackgroundDrawable(new BitmapDrawable(bg));
}
I used the cheesesquare demo to test this out.
First I started with a custom view for the triangle.
Note that you have to add a color named background to your colors.xml -or- use the color you have configured for the list background instead.
public class TriangleView extends View {
private Path mPath = new Path();
private Paint mPaint = new Paint();
public TriangleView(Context context) {
super(context);
}
public TriangleView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TriangleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#TargetApi(21)
public TriangleView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
mPath.reset();
mPath.moveTo(0,0);
mPath.lineTo(0, getHeight());
mPath.lineTo(getWidth(), getHeight());
mPath.close();
int backgroundColor = getResources().getColor(R.color.background);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(backgroundColor);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawPath(mPath, mPaint);
}
}
Here's how I worked it into the layout. The triangle covers the bottom corner of the image. This is just the collapsing toolbar portion of the layout:
<android.support.design.widget.CollapsingToolbarLayout
android:id="#+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleMarginStart="48dp"
app:expandedTitleMarginEnd="64dp">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:layout_collapseMode="none">
<ImageView
android:id="#+id/backdrop"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop" />
<com.example.fixme.TriangleView
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_gravity="bottom"/>
</FrameLayout>
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
app:layout_collapseMode="pin" />
</android.support.design.widget.CollapsingToolbarLayout>
As long as you don't need parallax scrolling on the image, this seems to work okay.

Android. Center text in TextView vertically

I have a ViewGroup class which adds a custom View and draws a pie chart on a canvas. In the center of the circle i have a TextView. But whatever i do, i cannot get the text in the TextView centered vertically.
The Root view in this case is a LinearLayout.
Snippet:
public class PieChart extends ViewGroup {
public PieChart(Context context) {
super(context);
mPieView = new PieView(getContext());
addView(mPieView);
}
...
private class PieView extends View {
public PieView(Context context) {
super(context);
text = new TextView(getContext());
text.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.FILL_PARENT));
text.setHeight(400);
text.setText(getCenterTextValue());
text.setTextColor(Color.BLACK);
text.setGravity(Gravity.CENTER);
text.setBackgroundColor(Color.GRAY);
addView(text);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
text.layout((int)mBoundsInner.left, (int)mBoundsInner.top, (int)mBoundsInner.right, (int)mBoundsInner.bottom);
}
}
...
}
This is how it looks like in the emulator. I have set a grey background for demonstration purposes so that you can see the bounds of the TextView
Picture of how it looks like in android emulator
Here is the activity.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:ls="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:gravity="center"
android:orientation="vertical" >
<com.lifescraper.view.PieChart
android:id="#+id/Pie"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:width="0dip">
</com.lifescraper.view.PieChart>
</LinearLayout>

Rectangle not appearing on the right

I'm trying to create a rectangle within a canvas so that it appears on the right hand side of the screen but the app seems to crash every time I run it. I seriously don't know am I doing wrong here + what needs to change within my code?
activity_main.xml
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
tools:context=".MainActivity">
<TextView android:text="#string/hello_world" android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<com.apptacularapps.customview.DrawView
android:id="#+id/diagram"
android:layout_width="fill_parent"
android:layout_height="52dp" />
</LinearLayout>
MainActivity.java
import android.graphics.Color;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DrawView drawView = new DrawView(this);
drawView.setBackgroundColor(Color.BLACK);
setContentView(drawView);
}
}
DrawView.java
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;
public class DrawView extends View {
Paint paint = new Paint();
Context context;
public DrawView(Context context) {
super(context);
this.context = context;
}
#Override
public void onDraw(Canvas canvas) {
//Code to Measure the Screen width in pixels
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
paint.setColor(Color.RED);
canvas.drawRect(0, 0, 5, canvas.getHeight(), paint );
paint.setColor(Color.RED);
canvas.drawRect(canvas.getWidth()-width, 0, 5, canvas.getHeight(), paint );
}
}
My earlier answer was because of my lack of understanding of your problem. Sorry for the inconvenience caused, if any. I am not sure if i can help you, but try this.
public void onDraw(Canvas canvas) {
//Code to Measure the Screen width in pixels
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
paint.setColor(Color.RED);
canvas.drawRect(0, 0, 5, canvas.getHeight(), paint );
paint.setColor(Color.RED);
canvas.drawRect(canvas.getWidth()-width, 0, 5, canvas.getHeight(), paint );
}
In the above piece of code, in the last line, instead of canvas.getWidth()-width, type canvas.getWidth()-(float) width. Because width is integer and canvas.getWidth() returns float and float-int returns a recurring floating number.
Check the value of width. Is it as expected ? Also try setting the value width manually and see if the problem persists.
Hope this helps and solves the trouble !
Have a look at this question and its accepted answer.
try this..
<com.example.mystackoverflow.MyView
android:id="#+id/myview"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_alignParentTop="true" />
MyView class
public class MyView extends View {
private Paint mPaint;
private int view_width, view_height;
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
mPaint.setColor(getResources().getColor(color.Red));
mPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//canvas.drawRect(0, 0, view_width, view_height, mPaint);
canvas.drawRect(view_width/2, 0, view_width, view_height, mPaint);
}
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
view_width = right - left;
view_height = bottom - top;
}
}

Categories

Resources