I am trying to implement an imageview with a diagonal cut at the bottom that I will user to display images on my app. This is the approach I take
I create a custom class that extends the ImageView.
I then override the onDraw method to draw the shape(This is where I'm not sure if I'm doing the correct thing
My custom imageview class
public class DiagonalSquare extends ImageView {
private Context mContext;
Paint paint ;
Path path;
public DiagonalSquare(Context context, AttributeSet attrs) {
super(context, attrs);
this.mContext = context;
setWillNotDraw(false);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
}
#Override
protected void onDraw(Canvas canvas) {
int w = getWidth(), h = getHeight();
paint.setStrokeWidth(2);
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.FILL_AND_STROKE);
paint.setAntiAlias(true);
path = new Path();
path.setFillType(Path.FillType.EVEN_ODD);
path.moveTo(w,h*3/4);
path.lineTo(w,h);
path.lineTo(0,h);
path.close();
canvas.drawPath(path, paint);
}
}
This is what I end up getting - blue section is the imageview. Here is the xml for that
<com.noel.CustomShape.DiagonalSquare
android:id="#+id/background_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:scaleType="centerCrop"
app:layout_collapseMode="parallax"
android:src="#drawable/bebe" />
You are missing a call to super.onDraw(canvas);
In addition to #Dimezis answer: If you want to have transparent effect on the ImageView background you have to clear hardware layer type and also set Xfermode for pain like in following example:
package com.j2ko.customviews;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.util.AttributeSet;
import android.widget.ImageView;
public class CustomImageView extends ImageView {
private Context mContext;
Paint paint ;
Path path;
public CustomImageView(Context context, AttributeSet attrs) {
super(context, attrs);
this.mContext = context;
setWillNotDraw(false);
//Move to XML if needed
setBackgroundColor(Color.TRANSPARENT);
setLayerType(LAYER_TYPE_HARDWARE, null);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int w = getWidth(), h = getHeight();
paint.setStrokeWidth(2);
paint.setColor(Color.WHITE);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
paint.setStyle(Paint.Style.FILL_AND_STROKE);
paint.setAntiAlias(true);
path = new Path();
path.setFillType(Path.FillType.EVEN_ODD);
path.moveTo(w,h*3/4);
path.lineTo(w,h);
path.lineTo(0,h);
path.close();
canvas.drawPath(path, paint);
}
}
This will give the following results:
Related
I am trying to make an application that needs draw a line while I drag an ImageView in a screen. I tried to create a canvas under the LinearLayouts, but it doesn't draw when I drag the object. Please help me! Here's the code from the MainActivity, the CanvasView class and the xml file. I don't how I should call the onTouchEvent method form the CanvasView class. When I touch the icon, it creates a shadow but don't draw the line than I expected.
package com.example.drawview;
import androidx.appcompat.app.AppCompatActivity;
import androidx.constraintlayout.widget.ConstraintLayout;
import android.content.ClipData;
import android.content.Context;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
public class MainActivity extends AppCompatActivity {
private CanvasView canvasView;
private ConstraintLayout mainLayout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.imageView).setOnTouchListener(new TouchEventView(this));
mainLayout = findViewById(R.id.screen);
canvasView = (CanvasView) findViewById(R.id.canvas);
}
public class TouchEventView extends View implements View.OnTouchListener {
public TouchEventView(Context context) {
super(context);
}
#Override
public boolean onTouch(View ve, MotionEvent event) {
canvasView.onTouchEvent(event);
ClipData data = ClipData.newPlainText("simple_text", "text");
View.DragShadowBuilder sb = new View.DragShadowBuilder(ve);
ve.startDrag(data, sb, ve, 0);
return true;
}
}
}
package com.example.drawview;
import android.content.ClipData;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.Nullable;
public class CanvasView extends View {
public int height;
public int width;
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mPaint;
private float mX, mY;
private final float TOLERANCE = 5;
Context context;
public CanvasView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
this.context = context;
mPath = new Path();
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(Color.GREEN);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeWidth(4f);
}
/*
public CanvasView(Context context) {
super(context);
this.context = context;
mPath = new Path();
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(Color.GREEN);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeWidth(4f);
}
*/
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawPath(mPath, mPaint);
}
private void startTouch(float x, float y){
mPath.moveTo(x, y);
mX = x;
mY = y;
}
private void moveTouch(float x, float y){
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if(dx >= TOLERANCE || dy >= TOLERANCE){
mPath.quadTo(mX, mY,(x + mX)/2, (y + mY)/2);
mX = x;
mY = y;
}
}
public void clearCanvas(){
mPath.reset();
invalidate();
}
private void upTouch(){
mPath.lineTo(mX, mY);
}
public boolean onTouchEvent(MotionEvent event) {
float xPos = event.getX();
float yPos = event.getY();
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
startTouch(xPos, yPos);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
moveTouch(xPos, yPos);
invalidate();
break;
case MotionEvent.ACTION_UP:
upTouch();
invalidate();
break;
}
return true;
}
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:id="#+id/screen"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.example.drawview.CanvasView
android:id="#+id/canvas"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />
<ImageView
android:id="#+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="#string/todo"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#drawable/ic_launcher_foreground" />
</androidx.constraintlayout.widget.ConstraintLayout>
It's an old book and has this example of drawing on the screen. So after typing the whole program, it's not behaving as it was said in the books that I'll allow you to draw on the screen.
import androidx.appcompat.app.AppCompatActivity;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.os.Bundle;
import android.provider.Settings;
import android.provider.Settings.Panel;
import android.view.MotionEvent;
import android.view.View;
import java.util.ArrayList;
import java.util.List;
public class dragAndDrawActivity extends Activity
{
Paint paint;
Point point1, point2;
Path path;
List<Path> paths=new ArrayList<Path>();
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(new Panel(this));
}
class Panel extends View implements View.OnTouchListener{
public Panel(Context context)
{
super(context);
paint=new Paint();
paint.setColor(Color.GREEN);
paint.setStrokeWidth(10);
paint.setStyle(Paint.Style.STROKE);
this.setOnTouchListener(this);
}
#Override
public void onDraw(Canvas canvas)
{
canvas.drawColor(Color.BLACK);
for (Path path: paths)
{
canvas.drawPath(path,paint);
}
}
#Override
public boolean onTouch(View view,MotionEvent event)
{
if(event.getAction()==MotionEvent.ACTION_DOWN)
{
point1=new Point();
point1.x=(int) event.getX();
point1.y=(int) event.getY();
path.moveTo(point1.x, point1.y);
}
else if(event.getAction()==MotionEvent.ACTION_MOVE)
{
point2 =new Point();
point2.x=(int) event.getX();
point2.y=(int) event.getY();
path.lineTo(point2.x, point2.y);
paths.add(path);
invalidate();
}
return true;
}
}
}
Build gets successful and apk install, but when you try to draw something on the screen, nothing happens.
and the background color also does not apply so there must be some issue with this code.
You should extract it to a custom view and add it to activity layout with alignment constrains. Furthermore, you need to init path variable before using it.
This is how I write it with Kotlin, you can convert back to Java
Panel class
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import androidx.annotation.Nullable
class Panel : View, View.OnTouchListener {
var paint: Paint? = null
var point1: Point? = null
var point2:Point? = null
var path: Path = Path()
var paths: ArrayList<Path> = ArrayList()
init {
paint = Paint()
paint?.color = Color.GREEN
paint?.strokeWidth = 10f
paint?.style = Paint.Style.STROKE
this.setOnTouchListener(this)
}
constructor(context: Context): super(context)
constructor(context: Context, #Nullable attrs: AttributeSet): super(context, attrs)
override fun onDraw(canvas: Canvas) {
canvas.drawColor(Color.BLACK)
paint?.let {
for (path in paths) {
canvas.drawPath(path, it)
}
}
}
override fun onTouch(view: View, event: MotionEvent): Boolean {
if (event.action == MotionEvent.ACTION_DOWN) {
point1 = Point()
point1?.x = event.x.toInt()
point1?.y = event.y.toInt()
path.moveTo((point1?.x?:0)*1f, (point1?.y?:0)*1f)
} else if (event.action == MotionEvent.ACTION_MOVE) {
point2 = Point()
point2?.x = event.x.toInt()
point2?.y = event.y.toInt()
path.lineTo((point2?.x?:0)*1f, (point2?.y?:0)*1f)
path.let {
paths.add(it)
}
invalidate()
}
return true
}
}
activity layout
<androidx.constraintlayout.widget.ConstraintLayout
android:clipToPadding="false"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white">
<com.martin.screst.customviews.Panel
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/colorPrimary"/>
</androidx.constraintlayout.widget.ConstraintLayout>
Activity class
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
Hey guys I'm trying to use this library (https://github.com/davemorrissey/subsampling-scale-image-view) and I tried out the example mentioned about PinView but I don't get the map displayed nor any Marker. ( the error says cannot cast Subsampling ImageView as PinView how do you solve this ?
MainActivity.java
package com.ascot.mxiv.mapzone;
import android.graphics.PointF;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView;
import com.davemorrissey.labs.subscaleview.ImageSource;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
PinView imageView = findViewById(R.id.imageView);
imageView.setImage(ImageSource.resource(R.drawable.completemap1).tilingDisabled());
imageView.setPin(new PointF(460f, 320f));
}
}
PinView.java ( no changes made other than the import test.T.drawable as i dont understand it ) and help would be appreciated :D .
import android.content.Context;
import android.graphics.*;
import android.util.AttributeSet;
import android.widget.Toast;
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView;
//import com.davemorrissey.labs.subscaleview.test.R.drawable;
public class PinView extends SubsamplingScaleImageView {
private final Paint paint = new Paint();
private final PointF vPin = new PointF();
private PointF sPin;
private Bitmap pin;
Context context;
public PinView(Context context) {
this(context, null);
this.context = context;
}
public PinView(Context context, AttributeSet attr) {
super(context, attr);
this.context = context;
initialise();
}
public void setPin(PointF sPin) {
this.sPin = sPin;
initialise();
invalidate();
}
private void initialise() {
float density = getResources().getDisplayMetrics().densityDpi;
pin = BitmapFactory.decodeResource(this.getResources(), R.drawable.marker);
float w = (density/420f) * pin.getWidth();
float h = (density/420f) * pin.getHeight();
pin = Bitmap.createScaledBitmap(pin, (int)w, (int)h, true);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// Don't draw pin before image is ready so it doesn't move around during setup.
if (!isReady()) {
return;
}
paint.setAntiAlias(true);
if (sPin != null && pin != null) {
sourceToViewCoord(sPin, vPin);
float vX = vPin.x - (pin.getWidth()/2);
float vY = vPin.y - pin.getHeight();
canvas.drawBitmap(pin, vX, vY, paint);
Toast.makeText(context,"works ? ", Toast.LENGTH_SHORT).show();
}
}
}
The problem is your in your layout, you should use PinView instead of SubsamplingScaleImageView as shown in the snippet below.
..
<com.example.myapp.PinView
android:id="#+id/floorplan_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
I'm using a relative layout with pinching zoom gestures enabled (The code is provided below in ZoomableViewGroup.java). And when I pinch it the quality of the TextView within it reduces. The structure of the project is very simple it has a MainActivity with the layout of main_activity.xml which the code is provided below.
main_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<com.example.test.ZoomableViewGroup
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:id="#+id/activity">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Hello"/>
</com.example.test.ZoomableViewGroup>
ZoomableViewGroup.java
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.widget.RelativeLayout;
public class ZoomableViewGroup extends RelativeLayout {
private ScaleGestureDetector mScaleDetector;
private float mScaleFactor = 1;
public ZoomableViewGroup(Context context) {
super(context);
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
}
public ZoomableViewGroup(Context context, AttributeSet attrs) {
this(context, attrs, 0);
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
}
public ZoomableViewGroup(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
}
#Override
public boolean onTouchEvent(MotionEvent event) {
mScaleDetector.onTouchEvent(event);
return true;
}
protected void dispatchDraw(Canvas canvas) {
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.scale(mScaleFactor, mScaleFactor);
super.dispatchDraw(canvas);
canvas.restore();
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
#Override
public boolean onScale(ScaleGestureDetector detector) {
mScaleFactor *= detector.getScaleFactor();
// Apply limits to the zoom scale factor:
invalidate();
requestLayout();
return true;
}
}
}
I have a customview where i display two rectangles. i want to set the height by a variable i sent from the mainactivity.
my customview class is the following.
package com.example.customview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
public class MyView extends View {
Paint paint;
Paint paint2;
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
paint = new Paint();
paint2 = new Paint();
}
#Override
protected void onDraw(Canvas canvas) {
paint.setColor(Color.RED);
paint2.setColor(Color.DKGRAY);
canvas.drawRect(150, 0, 200, 100, paint);
canvas.drawRect(200, 0, 250, 150, paint2);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(400, 300);
}
}
And the mainclass is standard
package com.example.customview;
import android.app.Activity;
import android.os.Bundle;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
how can i change the height from the oncreate or onstart.
Thanks all for helping.
You need create a varibale and set it from Activity. For example:
private int mHeight = 0;
#Override
protected void onDraw(Canvas canvas) {
paint.setColor(Color.RED);
paint2.setColor(Color.DKGRAY);
canvas.drawRect(150, 0, 200, 150 + mHeight, paint);
canvas.drawRect(200, 0, 250, 200 + mHeight, paint2);
}
public void setRectHeight(final int height) {
mHeight = height;
invalidate();
}
And set the height in your activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyView view = (MyView)findViewById(R.id.my_view);
view.setHeight(50);
}
you need to send data from main activity and receive it from MyView. when you create the intent for opening new activity from main use
_YourIntent_.putExtra(_tag_,_yourData_);
startActivityForResult(_YourIntent_, result);
//put extra is simply for sending data, and to receive it the other hand , oncreate use this;
Intent x = getIntent();``
//now get the data
int _yourvariable_ = x.getExtras().getString(_tag_).toint;