I am trying to draw a rectangle on top of an image in an ImageView. If I specifify (top, left) as (100, 100) and (bottom, right) = (200, 200) I get this:
As you can see it is not a square. How do I get that?
Here is the code for drawing:
private fun drawRectangle(
color: Int,
bitmap: Bitmap
) {
var image_view: ImageView = findViewById(R.id.image)
val tempBitmap =
Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888)
var canvas: Canvas = Canvas(tempBitmap)
val matrix: Matrix = Matrix()
val bitmap_paint: Paint = Paint(Color.TRANSPARENT)
canvas.drawBitmap(bitmap, matrix, bitmap_paint)
var shapeDrawable: ShapeDrawable
// rectangle positions
var left = 100
var top = 100
var right = 200
var bottom = 200
// draw rectangle shape to canvas
shapeDrawable = ShapeDrawable(RectShape())
shapeDrawable.setBounds( left, top, right, bottom)
shapeDrawable.getPaint().setColor(color)
shapeDrawable.getPaint().setStyle(Paint.Style.STROKE)
shapeDrawable.draw(canvas)
image_view.background = BitmapDrawable(getResources(), tempBitmap)
}
and the xml file:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
tools:context=".MainActivity">
<ImageView
android:id="#+id/image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitCenter" />
<TextView
android:id="#+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:textSize="18sp"
android:background="#80000000"
android:textColor="#android:color/white" />
</FrameLayout>
The problem is that you are using ImageView.background property and "match_parent" for your ImageView.
And parent have rectangular shape which you are using to get width and height for your new bitmap and canvas so ImageView also being stretched.
If you change ImageView width and height to "wrap_content" or to specific size it will give you square square.
Better results will be achieved if you use setImageBitmap instead of "background.
eg change line
image_view.background = BitmapDrawable(getResources(), tempBitmap)
to
image_view.setImageBitmap( tempBitmap)
Related
I have to implement a banner according to the following designs:
The complexity here is in the shadow of the round logo, the shadow of the logo circle is the continuation of the shadow of the rectangular card of the banner. The border of the shadow is outlined in the following image:
Of course the shadow shouldn't be casted on the surface below the top side of the card. Also the logo center has some offset from the border of the card.
How can I achieve this effect? Standard android shapes doesn't allow to form such a contour. Drawing everything manually seems to be too complex decision for the problem. We have minSdkVersion 21.
You can achieve it using this trick
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.cardview.widget.CardView
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="20dp"
app:cardCornerRadius="56dp"
app:cardElevation="16dp"
android:layout_width="56dp"
android:layout_height="56dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<de.hdodenhof.circleimageview.CircleImageView
android:layout_width="match_parent"
android:src="#color/colorPrimary"
android:layout_height="match_parent"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
app:cardElevation="16dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="48dp"
android:layout_width="350dp"
android:layout_height="500dp">
<LinearLayout
android:layout_marginTop="-28dp"
android:layout_gravity="center_horizontal"
android:layout_width="56dp"
android:layout_height="56dp">
<de.hdodenhof.circleimageview.CircleImageView
android:layout_width="match_parent"
android:src="#color/colorPrimary"
android:layout_height="match_parent"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>
The result will be:
The main idea create two cardview with images, one under the main card and another one in the cardview and using margins make the look like one circle.
I've ended up on using the MaterialShapeDrawable class. It allows to customize drawable edges by manually defining how the edge should de drawn. This is achieved by deriving EdgeTreatment class (similar is possible for corners with CornerTreatment).
As a result the background of the banner looks like this:
Here is the banner top edge treatment class:
private class BannerTopEdgeTreatment(private val circleRadius: Int,
private val circleCenterOffset: Int) : EdgeTreatment(), Cloneable {
init {
// do not allow to offset circle center up
if (circleCenterOffset < 0)
throw IllegalArgumentException()
}
override fun getEdgePath(length: Float, center: Float, interpolation: Float, shapePath: ShapePath) {
// use interpolated radius
val radius = circleRadius * interpolation
// if circle lays entirely inside the rectangle then just draw a line
val circleTop = circleCenterOffset - radius
if (circleTop >= 0) {
shapePath.lineTo(length, 0f)
return
}
// calc the distance from the center of the edge to the point where arc begins
// ignore the case when the radius is so big that the circle fully covers the edge
// just draw a line for now, but maybe it can be replaced by drawing the arc
val c = sqrt(radius.pow(2) - circleCenterOffset.toDouble().pow(2))
if (c > center) {
shapePath.lineTo(length, 0f)
return
}
// draw a line from the left corner to the start of the arc
val arcStart = center - c
shapePath.lineTo(arcStart.toFloat(), 0f)
// calc the start angle and the sweep angle of the arc and draw the arc
// angles are measured clockwise with 0 degrees at 3 o'clock
val alpha = Math.toDegrees(asin(circleCenterOffset / radius).toDouble())
val startAngle = 180 + alpha
val sweepAngle = 180 - 2 * alpha
shapePath.addArc(
center - radius,
circleCenterOffset - radius,
center + radius,
circleCenterOffset + radius,
startAngle.toFloat(),
sweepAngle.toFloat())
// draw the line from the end of the arc to the right corner
shapePath.lineTo(length, 0f)
}
}
The method to construct a background drawable for banner:
fun createBannerBackgroundDrawable(backgroundColor: ColorStateList,
#Px circleRadius: Int,
#Px circleCenterOffset: Int,
#Px cornersRadius: Int,
#Px elevation: Int): Drawable {
val appearanceModel = ShapeAppearanceModel.builder()
.setTopEdge(BannerTopEdgeTreatment(circleRadius, circleCenterOffset))
.setAllCorners(CornerFamily.ROUNDED, cornersRadius.toFloat())
.build()
val drawable = MaterialShapeDrawable(appearanceModel)
drawable.fillColor = backgroundColor
drawable.elevation = elevation.toFloat()
return drawable
}
Then this drawable is used as a background of the banner view:
banner.background = createVerticalBannerBackground(...)
And also it is necessary to set clipChildren attribute of the parent view of the banner to false:
android:clipChildren="false"
The final result:
Well my app should let me take a picture of my face and display it until i delete it where I can take another one. What is happening when I first open the app is that the pink side lines of the layout backround shows but when I take a picture the pink lines dissapear. This shouldnt happen because the imageview that i am setting the backround bitmap to is match_parent on width and height
The second problem is that the when I set the background imageview back to the background before which is transparent in the center so you can see where the camera is pointing does not happen even though I set it back. The screen should revert back to the transparent center but it stays the screenshot that is taken when takePicture is run. Thanks for any help as i am ripping my hair out right now
background_view = (ImageView) view.findViewById(R.id.backround_view);
background = BitmapFactory.decodeResource(getResources(), R.drawable.camera_backround);
background_view.setImageBitmap(background);
private void takePicture() {
if (picturePresent == false) {
edit_button.setVisibility(View.INVISIBLE);
pictureBitmap = getBitmapFromView();
edit_button.setVisibility(View.VISIBLE);
closeCamera();
stopBackgroundThread();
BitmapDrawable bitmapDrawable = new BitmapDrawable(getResources(), pictureBitmap);
background_view.setBackground(bitmapDrawable);
picturePresent = true;
} else {
}
}
private void deletePicture() {
if (picturePresent == true) {
startBackgroundThread();
openCamera(mTextureView.getWidth(), mTextureView.getHeight());
background_view.setImageBitmap(background);
picturePresent = false;
} else {
}
}
public Bitmap getBitmapFromView() {
Bitmap bitmap = mTextureView.getBitmap();
Bitmap bitmap2 = BitmapFactory. decodeResource(getResources(), R.drawable.camera_backround);
Bitmap bmOverlay = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig());
Canvas canvas = new Canvas(bmOverlay);
canvas.drawBitmap(bitmap, new Matrix(), null);
canvas.drawBitmap(bitmap2, new Matrix(), null);
return bmOverlay;
}
XML
<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"
tools:context="yourfacelivewallpaper.alexcz.yourfacelivewallpaper.CameraFragment"
android:background="#ffbf1ec5">
<!-- TODO: Update blank fragment layout -->
<view
android:layout_width="fill_parent"
android:layout_height="fill_parent"
class="yourfacelivewallpaper.alexcz.yourfacelivewallpaper.AutoFitTextureView"
android:id="#+id/texture"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"/>
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/backround_view"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:longClickable="false"
android:layout_alignParentEnd="true"
android:layout_alignParentStart="true"/>
android:scaleType="fitXY"
Add above code in xml file.
If your image is smaller than your ImageView it won't fill the screen. You should add android:scaleType="fitCenter" to your ImageView's layout properties.
I have a picture (jpg) that I want to display on the screen.
Additionally the picture should be covered partially by a transparent effect.
The transparent cover should be dynamic. So e.g. each day more of the picture is shown.
Here a picture to show what I mean:
I have the picture without the gray cover and want to add this cover but in different steps.
Can someone give me a hint how to do that.
You can do this simply with widgets:
FrameLayout is the general mechanism for overlaying a view on top of another:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/my_image"/>
<View
android:id="#+id/overlay"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</FrameLayout>
Then in your Java code you can dynamically set the transparency of your overlay:
View overlay = (View) findViewById(R.id.overlay);
int opacity = 200; // from 0 to 255
overlay.setBackgroundColor(opacity * 0x1000000); // black with a variable alpha
FrameLayout.LayoutParams params =
new FrameLayout.LayoutParams(FrameLayout.LayoutParams.FILL_PARENT, 100);
params.gravity = Gravity.BOTTOM;
overlay.setLayoutParams(params);
overlay.invalidate(); // update the view
You can do something like this where the canvas is coming from an onDraw() request:
Paint paint = new Paint();
Rect r = new Rect();
paint.setColor(0x80808080); // translucent gray
r.right = iDisplayWidth-1;
r.left = 0;
r.top = iDisplayHeight/2;
r.bottom = iDisplayHeight-1;
canvas.drawRect(r, paint); // fill with gray
I have a picture (jpg) that I want to display on the screen.
Additionally the picture should be covered partially by a transparent effect.
The transparent cover should be dynamic. So e.g. each day more of the picture is shown.
Here a picture to show what I mean:
I have the picture without the gray cover and want to add this cover but in different steps.
Can someone give me a hint how to do that.
You can do this simply with widgets:
FrameLayout is the general mechanism for overlaying a view on top of another:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/my_image"/>
<View
android:id="#+id/overlay"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</FrameLayout>
Then in your Java code you can dynamically set the transparency of your overlay:
View overlay = (View) findViewById(R.id.overlay);
int opacity = 200; // from 0 to 255
overlay.setBackgroundColor(opacity * 0x1000000); // black with a variable alpha
FrameLayout.LayoutParams params =
new FrameLayout.LayoutParams(FrameLayout.LayoutParams.FILL_PARENT, 100);
params.gravity = Gravity.BOTTOM;
overlay.setLayoutParams(params);
overlay.invalidate(); // update the view
You can do something like this where the canvas is coming from an onDraw() request:
Paint paint = new Paint();
Rect r = new Rect();
paint.setColor(0x80808080); // translucent gray
r.right = iDisplayWidth-1;
r.left = 0;
r.top = iDisplayHeight/2;
r.bottom = iDisplayHeight-1;
canvas.drawRect(r, paint); // fill with gray
How do you programmatically set the width of an ImageView inside a TableRow? I do NOT want the cell width to change, only the width of the image inside the cell.
Layout: (The ellipsis are there to reduce the code)
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal">
<TableRow android:gravity="center_vertical">
<Button>...</Button>
<ImageView
android:id="#+id/fruit"
android:layout_width="120dp"
android:layout_height="44dp"
android:src="#drawable/apple"
android:scaleType="matrix"
></ImageView>
<Button>...</Button>
</TableRow>
<TableRow>...</TableRow>
</TableLayout>
Java:
ImageView iv = (ImageView) findViewById(R.id.fruit);
LayoutParams frame = iv.getLayoutParams();
frame.width = 100;
iv.setLayoutParams(frame);
EDIT: i want the image to be cropped inside the bounds i set and have the table cell be the original width. Below is the code example that worked for me thanks to parag's suggestion:
Bitmap bmp = BitmapFactory.decodeResource(getResources() , R.drawable.apple);
int width = 50;
int height = 44;
Bitmap resizedbitmap = Bitmap.createBitmap(bmp, iv.getScrollX(), iv.getScrollY(), width, height);
iv.setImageBitmap(resizedbitmap);
Another way that u resized the bitmap
ImageView img=(ImageView)findViewById(R.id.ImageView01);
Bitmap bmp=BitmapFactory.decodeResource(getResources(), R.drawable.sc01);
int width=200;
int height=200;
Bitmap resizedbitmap=Bitmap.createScaledBitmap(bmp, width, height, true);
img.setImageBitmap(resizedbitmap);
Do you want to scale the image? Or crop it?
To scale, try ImageView.setImageMatrix and Matrix.preScale.
If you don't want to figure out the Matrices, you could try Rects (bounding boxes). Get the original rect with ImageView.getDrawingRect and then define whatever Rect you want and use Matrix.setRectToRect to create your image matrix.
Otherwise, have you tried ImageView.setMaxWidth?