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>
Related
Good Evening,
I minimized my large project onto a small scale one which still keeps all the aspects of issue I'm having. I'm using an activity that draws SurfaceView background underneath a single Button. On press that Button adds a new fragment (to an empty FrameLayout that's in MainActivities XML layout) which as well holds SurfaceView and three buttons in ConstraintLayout. Button works as intended and calls the Fragments, but only the static layout part is being drawn(three buttons) as for SurfaceView it only draws Initial Canvas and keeps redrawing same Frame, even tho Thread keeps on calling the Draw method with updated values(in this case Color). ThreadPool is used to create two instances that call update and draw methods for SurfaceView(MaintActivity and Fragment) class objects(this part works as intended).
I'm also getting this line in Log, right about where the issue begins.
D/MY FRAGMENT VIEW: >> INIT
D/MY FRAGMENT VIEW: SURFACE CREATED
D/MY_FRAGMENT: SURFACE CREATED
D/MY FRAGMENT VIEW: SURFACE CHANGED
D/MY_FRAGMENT: SURFACE CHANGED
D/MY FRAGMENT VIEW: DRAW PLANET
D/: HostConnection::get() New Host Connection established 0xb2d1d780, tid 9982
D/MY FRAGMENT VIEW: DRAW PLANET
D/MY FRAGMENT VIEW: DRAW PLANET
D/MY FRAGMENT VIEW: DRAW PLANET
D/MY FRAGMENT VIEW: DRAW PLANET
Code samples bellow:
package com.badcompany.testfragmentview;
import android.os.Bundle;
import android.support.constraint.ConstraintLayout;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback {
private MyActivityView gameView;
private static final String TAG = "MAIN";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
gameView = findViewById(R.id.myview);
SurfaceHolder gholder = gameView.getHolder();
gholder.addCallback(this);
gameView.setLayoutParams(new ConstraintLayout.LayoutParams(ConstraintLayout.LayoutParams.WRAP_CONTENT, ConstraintLayout.LayoutParams.WRAP_CONTENT));
Button btn_map = findViewById(R.id.start);
btn_map.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
displayMapFragment();
return true;
}
return false;
}
});
}
#Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
Log.d(TAG, ">> SURFACE CREATED");
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
Log.d(TAG, ">> SURFACE CHANGED");
}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
Log.d(TAG, ">> SURFACE DESTROYED");
}
private void displayMapFragment() {
MyFragment myFragment = new MyFragment();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.myMapSpace, myFragment).addToBackStack(null)
.commit();
/*fragmentTransaction.add(R.id.fragment_container, simpleFragment).addToBackStack(null).commit();
mButton.setText(R.string.close);
isFragmentDisplayed = true;*/
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.badcompany.testfragmentview.MyActivityView
android:id="#+id/myview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<Button
android:id="#+id/start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<FrameLayout
android:id="#+id/myMapSpace"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
MyActivityView.java
package com.badcompany.testfragmentview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
public class MyActivityView extends ParentGameView implements SurfaceHolder.Callback {
private static final String TAG = "MY ACTIVITY VIEW";
public MyActivityView(Context context) {
super(context);
}
public MyActivityView(Context context, AttributeSet attrs) {
super(context, attrs);
getHolder().addCallback(this);
setFocusable(true);
}
public MyActivityView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public MyActivityView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
#Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
Log.d(TAG, "SURFACE CREATED");
MyExecutor.getInstance().execute(new GameRunnable(surfaceHolder, this));
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
Log.d(TAG, "SURFACE CHANGED");
}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
Log.d(TAG, "SURFACE DESTROYED");
}
#Override
public void draw(Canvas canvas) {
super.draw(canvas);
canvas.drawColor(Color.YELLOW);
Paint paint = new Paint();
paint.setColor(Color.RED);
canvas.drawCircle(x, 100, 200, paint);
}
}
MyFragment.java
package com.badcompany.testfragmentview;
import android.os.Bundle;
import android.support.constraint.ConstraintLayout;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.SurfaceHolder;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.Toast;
public class MyFragment extends Fragment implements SurfaceHolder.Callback {
private static final String TAG = "MY_FRAGMENT";
private MyFragmentView myFragmentView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstanceState) {
//AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
final View rootView = inflater.inflate(R.layout.fragment_my, viewGroup, false);
myFragmentView = rootView.findViewById(R.id.myMapView);
SurfaceHolder mSurfaceHolder = myFragmentView.getHolder();
mSurfaceHolder.addCallback(this);
myFragmentView.setLayoutParams(new ConstraintLayout.LayoutParams(ConstraintLayout.LayoutParams.WRAP_CONTENT, ConstraintLayout.LayoutParams.WRAP_CONTENT));
Button selectGalaxyMap = rootView.findViewById(R.id.btn_select_galaxy_map);
Button selectSolarSystemMap = rootView.findViewById(R.id.btn_select_solar_map);
Button selectPlanetMap = rootView.findViewById(R.id.btn_select_planet_map);
selectGalaxyMap.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.d(TAG, "SELECTED GALAXY");
myFragmentView.setColor(1);
Toast.makeText(getActivity(), "SELECT GALAXY", Toast.LENGTH_SHORT).show();
}
});
selectSolarSystemMap.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
myFragmentView.setColor(2);
Log.d(TAG, "SELECTED SYSTEM");
Toast.makeText(getActivity(), "SELECT SYSTEM", Toast.LENGTH_SHORT).show();
}
});
selectPlanetMap.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(getActivity(), "SELECT PLANET", Toast.LENGTH_SHORT).show();
myFragmentView.setColor(3);
Log.d(TAG, "SELECTED PLANET");
}
});
return rootView;
}
#Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
Log.d(TAG, "SURFACE CREATED");
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
Log.d(TAG, "SURFACE CHANGED");
}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
Log.d(TAG, "SURFACE DESTROYED");
}
}
fragment_my.xml
<com.badcompany.testfragmentview.MyFragmentView
android:id="#+id/myMapView"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:background="#color/colorPrimary"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<Button
android:id="#+id/btn_select_planet_map"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:background="#null"
android:text="SELECT PLANET"
android:textStyle="bold" />
<Button
android:id="#+id/btn_select_solar_map"
app:layout_constraintRight_toLeftOf="#id/btn_select_planet_map"
app:layout_constraintTop_toTopOf="parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:background="#null"
android:text="SELET SYSTEM"
android:textStyle="bold" />
<Button
android:id="#+id/btn_select_galaxy_map"
app:layout_constraintRight_toLeftOf="#id/btn_select_solar_map"
app:layout_constraintTop_toTopOf="parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:background="#null"
android:text="SELECT GALAXY"
android:textStyle="bold" />
</android.support.constraint.ConstraintLayout>
package com.badcompany.testfragmentview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
public class MyFragmentView extends ParentGameView implements SurfaceHolder.Callback {
private static final String TAG = "MY FRAGMENT VIEW";
private int Colors;
public MyFragmentView(Context context) {
super(context);
init(context);
}
public MyFragmentView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public MyFragmentView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
public MyFragmentView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context);
}
private void init(Context context) {
getHolder().addCallback(this);
Log.d(TAG, ">> INIT ");
setFocusable(true);
}
#Override
public void draw(Canvas canvas) {
super.draw(canvas);
if(Colors == 2)
drawSolarMap(canvas);
else if(Colors == 1)
drawGalaxyMap(canvas);
else drawPlanetMap(canvas);
}
private void drawGalaxyMap(Canvas canvas){
Log.d(TAG, "DRAW GALAXY");
canvas.drawColor(Color.BLACK);
Paint paint = new Paint();
paint.setColor(Color.BLUE);
canvas.drawCircle(x, 100, 100, paint);
}
private void drawSolarMap(Canvas canvas){
Log.d(TAG, "DRAW SYSTEM");
canvas.drawColor(Color.RED);
Paint paint = new Paint();
paint.setColor(Color.BLUE);
canvas.drawCircle(x, 100, 100, paint);
}
private void drawPlanetMap(Canvas canvas){
Log.d(TAG, "DRAW PLANET");
canvas.drawColor(Color.GREEN);
Paint paint = new Paint();
paint.setColor(Color.BLUE);
canvas.drawCircle(x, 100, 100, paint);
}
#Override
public void update() {
super.update();
}
public void setColor(int color){
Colors = color;
}
#Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
Log.d(TAG, "SURFACE CREATED");
MyExecutor.getInstance().execute(new GameRunnable(surfaceHolder, this));
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
Log.d(TAG, "SURFACE CHANGED");
}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
Log.d(TAG, "SURFACE DESTROYED");
}
}
Extra classes that might not have relevance
GameInterface.java
package com.badcompany.testfragmentview;
/**
* Created by Donatas on 18/12/2018.
*/
import android.graphics.Canvas;
public interface GameInterface {
public void draw(Canvas canvas);
public void update();
}
ParentGameView.java
package com.badcompany.testfragmentview;
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.SurfaceView;
public class ParentGameView extends SurfaceView implements GameInterface{
private static final String TAG = "PARENT_GAME_VIEW";
protected int x = 0;
public ParentGameView(Context context) {
super(context);
}
public ParentGameView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ParentGameView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public ParentGameView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
#Override
public void update() {
x++;
}
#Override
public void draw(Canvas canvas){
super.draw(canvas);
}
}
MyExecutor.java
package com.badcompany.testfragmentview;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MyExecutor {
private static final ExecutorService executor = Executors.newCachedThreadPool();
public static ExecutorService getInstance(){
return executor;
}
public static void ShutDown(){
executor.shutdown();
}
}
GameRunnable.java
package com.badcompany.testfragmentview;
import android.graphics.Canvas;
import android.util.Log;
import android.view.SurfaceHolder;
public class GameRunnable implements Runnable {
private static final String TAG = "GAME_RUNNABLE";
private volatile boolean running = true;
private final int maxFPS = 30;
private double averageFPS;
private Canvas canvas;
private final SurfaceHolder surfaceHolder;
private volatile ParentGameView gameView;
public GameRunnable(SurfaceHolder surfaceHolder, ParentGameView gameView) {
this.surfaceHolder = surfaceHolder;
this.gameView = gameView;
}
#Override
public void run() {
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
long startTime;
long timeMillis = 1000/maxFPS;
long waitTime;
int frameCount = 0;
long totalTime = 0;
long targetTime = 1000/maxFPS;
while(running){
startTime = System.nanoTime();
canvas = null;
try {
canvas = surfaceHolder.lockCanvas();
if(canvas != null){
synchronized (surfaceHolder){
gameView.update();
gameView.draw(canvas);
}
} else {
Log.d(TAG, "Thread finished work");
return;
}
}
catch (Exception e){
e.printStackTrace();
}
finally {
if(canvas != null){
try{
surfaceHolder.unlockCanvasAndPost(canvas);
}catch (Exception e){e.printStackTrace();}
}
}
timeMillis = (System.nanoTime() - startTime)/1000000;
waitTime = targetTime - timeMillis;
try{
if(waitTime>0)
Thread.sleep(waitTime);
} catch (Exception e){e.printStackTrace();}
totalTime += System.nanoTime() - startTime;
frameCount++;
if(frameCount == maxFPS){
averageFPS = 1000/((totalTime/frameCount)/1000000);
frameCount = 0;
totalTime = 0;
//debug System.out.println("AVERAGE FPS: " + avaragFPS);
}
}
}
}
Thanks for looking into this and if you need additional info leave a comment.
Found an awful solution myself, the issue is that MainActivity does not ask for next frame because it deems fragment view to be finished, calling invalidate() method in a Thread makes the activity to keep on asking for updated views.
If you manage to find a better solution please update this post, thanks.
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:
I have an app that displays random characters vertically on the screen (like in the matrix movie) and I would like to add buttons to change the color of these chars when pressed, but I'm unable to call the method setColor of paintTxt variable from MainActivity.
This is my code,
EffetMatrix effetMatrix = new EffetMatrix();//Error in ()
final Paint paintTxt = effetMatrix.paintTxt;
paintTxt.setColor(Color.RED);
But the editor shows an error:
EffetMatrix(Context, AttributSet) in EffetMatrix cannot be applied to ()
the EffetMatrix class code
package com.esqmo.apps.effetmatrix;
import java.util.Random;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import android.content.Context;
import android.widget.Button;
/**
* Created by esQmo on 04/10/2016.
*/
public class EffetMatrix extends View {
private static final Random ALEATOIRE = new Random();
private int larg, haut;
private Canvas toile;
private Bitmap toileBmp;
private int taillePolice = 40;
private int tailleColonne;
private char[] chars = "01".toCharArray();
private int[] posTxtParColonne;
public Paint peindreTxt, peindreArrPlan, peindreArrPlanBmp, peindreInitArrPlan;
public EffetMatrix(Context context, AttributeSet attrs) {
super(context, attrs);
peindreTxt = new Paint();
peindreTxt.setStyle(Paint.Style.FILL);
peindreTxt.setColor(Color.BLUE);
peindreTxt.setTextSize(taillePolice);
peindreArrPlan = new Paint();
peindreArrPlan.setStyle(Paint.Style.FILL);
peindreArrPlan.setColor(Color.BLACK);
peindreArrPlan.setAlpha(5);
peindreArrPlanBmp = new Paint();
peindreArrPlanBmp.setColor(Color.BLACK);
peindreInitArrPlan = new Paint();
peindreInitArrPlan.setColor(Color.BLACK);
peindreInitArrPlan.setAlpha(255);
peindreInitArrPlan.setStyle(Paint.Style.FILL);
}
#Override
protected void onSizeChanged(int l, int h, int ancl, int anch) {
super.onSizeChanged(l, h, ancl, anch);
larg = l;
haut = h;
toileBmp = Bitmap.createBitmap(larg, haut, Bitmap.Config.ARGB_8888);
toile = new Canvas(toileBmp);
toile.drawRect(0, 0, larg, haut, peindreInitArrPlan);
tailleColonne = larg / taillePolice;
posTxtParColonne = new int[tailleColonne + 1];
for (int x = 0; x < tailleColonne; x++) {
posTxtParColonne[x] = ALEATOIRE.nextInt(larg / 2) + 1;
}
}
private void dessineTexte() {
for (int i = 0; i < posTxtParColonne.length; i++) {
toile.drawText("" + chars[ALEATOIRE.nextInt(chars.length)], i * taillePolice,
posTxtParColonne[i] * taillePolice, peindreTxt);
if (posTxtParColonne[i] * taillePolice > larg && Math.random() > 0.980) {
posTxtParColonne[i] = 0;
}
posTxtParColonne[i]++;
}
}
private void dessineToile() {
toile.drawRect(0, 0, larg, haut, peindreArrPlan);
dessineTexte();
}
#Override
protected void onDraw(Canvas toile) {
super.onDraw(toile);
toile.drawBitmap(toileBmp, 0, 0, peindreArrPlanBmp);
dessineToile();
invalidate();
}
public void setCustomColor(int color){
peindreTxt.setColor(color);
invalidate();
}
}
note: variable peindreText = paintText
The main activity code:
package com.esqmo.apps.effetmatrix;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.Paint;
import android.media.effect.Effect;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final Button boutton_vert = (Button) findViewById(R.id.b_v);
final Button boutton_bleu = (Button) findViewById(R.id.b_b);
final Button boutton_rouge = (Button) findViewById(R.id.b_r);
final Button boutton_rose = (Button) findViewById(R.id.b_ro);
boutton_bleu.setOnClickListener(this);
boutton_vert.setOnClickListener(this);
boutton_rouge.setOnClickListener(this);
boutton_rose.setOnClickListener(this);
}
#Override
public void onClick(View v) {
}
public void passerVert(View v) {
}
public void passerRouge(View v) {
}
public void passerRose(View v) {
}
public void passerBleu(View v) {
}
}
main.xml
<com.esqmo.apps.effetmatrix.EffetMatrix
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/arrPlan"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true"
android:background="#040404"
android:id="#+id/linearLayout">
<Button
android:layout_width="70dp"
android:layout_height="match_parent"
android:text="#string/button_vert"
android:onClick="passerVert"
android:id="#+id/b_v"
android:textAppearance="#android:color/holo_blue_dark" />
<Button
android:layout_width="70dp"
android:layout_height="match_parent"
android:text="#string/button_bleu"
android:onClick="passerBleu"
android:id="#+id/b_b"/>
<Button
android:layout_width="70dp"
android:layout_height="match_parent"
android:text="#string/button_rouge"
android:onClick="passerRouge"
android:id="#+id/b_r" />
<Button
android:layout_width="70dp"
android:layout_height="match_parent"
android:text="#string/button_rouge"
android:onClick="passerRose"
android:id="#+id/b_ro" />
</LinearLayout>
PS: I'm a noob in programming.
Sorry for my english
Don't create a new instance of the custom view again. Instead get a reference to the view using its id.
See the following code,
EffetMatrix effetMatrix = (EffetMatrix) findViewById(R.id.arrPlan);
effetMatrix.setCustomTextColor(Color.RED);
Inside EffetMatrix class create a method named setCustomColor as follows,
class EffetMatrix {
...
public void setCustomTextColor(int color){
// Set the color to the paintTxt object
paintTxt.setColor(color);
// invalidate the view to apply the changes
invalidate();
}
...
}
This is how you implement it in your code,
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
EffetMatrix effetMatrix;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
effetMatrix = (EffetMatrix) findViewById(R.id.arrPlan);
...
}
#Override
public void onClick(View v) {
switch(v.getId()){
case R.id.b_b:
effetMatrix.setCustomTextColor(Color.BLUE);
break;
case R.id.b_r:
effetMatrix.setCustomTextColor(Color.RED);
break;
case R.id.b_ro:
effetMatrix.setCustomTextColor(Color.MAGENTA);
break;
}
}
}
You must invalidate your custom view after changing paint color.
effetMatrix.invalidate();
And if you want to display your custom view in editor you must implement :
public EffetMatrix(Context context) {
this(context, null);
}
public EffetMatrix(Context context, AttributeSet attrs) {
super(context, attrs);
}
If you want to make the buttons do something, then you have to set an onClickListener for each button in your main properly. Here's an example for button_bleu,
Get rid of boutton_bleu.setOnClickListener(this); and replace it with
button_bleu.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
effetMatrix.setCustomColor(Color.BLUE);
}
});
Now just do the same for the other 3 buttons.
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 need help regarding the viewpager. Basically I have a viewpager contained in a page container:
package com.example.CustomViews;
/**
* Created by imrankhan on 4/29/2015.
*/
import android.content.Context;
import android.graphics.Camera;
import android.graphics.Matrix;
import android.graphics.Point;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.Transformation;
import android.widget.FrameLayout;
import android.widget.ImageView;
import com.example.imrankhan.newlawdojo.DashboardActivity;
import com.example.imrankhan.newlawdojo.QuizActivity;
import com.example.imrankhan.newlawdojo.R;
/**
* PagerContainer: A layout that displays a ViewPager with its children that are outside
* the typical pager bounds.
*/
public class PageContainer extends FrameLayout implements ViewPager.OnPageChangeListener {
private ViewPager mPager;
boolean mNeedsRedraw = false;
private Camera mCamera = new Camera();
private int mMaxRotationAngle = 60;
private int mMaxZoom = -120;
public PageContainer(Context context) {
super(context);
init();
}
public PageContainer(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public PageContainer(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
//Disable clipping of children so non-selected pages are visible
setClipChildren(false);
//Child clipping doesn't work with hardware acceleration in Android 3.x/4.x
//You need to set this value here if using hardware acceleration in an
// application targeted at these releases.
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
#Override
protected void onFinishInflate() {
try {
mPager = (ViewPager) getChildAt(0);
mPager.setOnPageChangeListener(this);
} catch (Exception e) {
throw new IllegalStateException("The root child of PagerContainer must be a ViewPager");
}
}
public ViewPager getViewPager() {
return mPager;
}
private Point mCenter = new Point();
private Point mInitialTouch = new Point();
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
mCenter.x = w / 4;
mCenter.y = h / 4;
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
//We capture any touches not already handled by the ViewPager
// to implement scrolling from a touch outside the pager bounds.
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mInitialTouch.x = (int)ev.getX();
mInitialTouch.y = (int)ev.getY();
default:
ev.offsetLocation(mCenter.x - mInitialTouch.x, mCenter.y - mInitialTouch.y);
break;
}
return mPager.dispatchTouchEvent(ev);
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
//Force the container to redraw on scrolling.
//Without this the outer pages render initially and then stay static
if (mNeedsRedraw) invalidate();
}
#Override
public void onPageSelected(int position) {
View v =this.getViewPager().getChildAt(position);
}
private void transformImageBitmap(View child, Transformation t, int rotationAngle) {
mCamera.save();
final Matrix imageMatrix = t.getMatrix();;
final int imageHeight = child.getLayoutParams().height;;
final int imageWidth = child.getLayoutParams().width;
final int rotation = Math.abs(rotationAngle);
mCamera.translate(0.0f, 0.0f, 100.0f);
if ( rotation < mMaxRotationAngle ) {
float zoomAmount = (float) (mMaxZoom + (rotation * 1.5));
mCamera.translate(0.0f, 0.0f, zoomAmount);
}
mCamera.rotateY(rotationAngle);
mCamera.getMatrix(imageMatrix);
imageMatrix.preTranslate(-(imageWidth/2), -(imageHeight/2));
imageMatrix.postTranslate((imageWidth/2), (imageHeight/2));
mCamera.restore();
}
#Override
public void onPageScrollStateChanged(int state) {
mNeedsRedraw = (state != ViewPager.SCROLL_STATE_IDLE);
}
}
on onPageSelected event I got the view I need to zoom in when selected and zoom out after selecting another item. Please help me out. I added an image to give you an idea what I want.
http://i.stack.imgur.com/xtE89.png