In my Application if the brush size is selected it changes the brush size but it also changes the size of the brush inside the canvas how to make it so that the brush size inside the canvas doesn't change.
This is my code for the EasyOne.Java - This contains contain the brushsizes:
import static com.example.artbit.display2.colorList1;
import static com.example.artbit.display2.currentbrush1;
import static com.example.artbit.display2.pathlist1;
public class EasyOne extends AppCompatActivity {
public static Path path1 = new Path();
public static Paint paintbrush1 = new Paint();
public static String brushsize1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_easy_one);
This is for the brushes
public void SmallBrush1(View view){
paintbrush1.setStrokeWidth(10f);
paintbrush1.setColor(Color.BLACK);
currentColor1(paintbrush1.getColor());
}
public static void BigBrush1(View view){
/* brushsize1 = "1";
paintbrush1.setColor(Color.BLACK);
currentColor1(paintbrush1.getColor());*/
paintbrush1.setStrokeWidth(50f);
currentColor1(paintbrush1.getColor());
}
public void Brush1(View view) {
MediaPlayer mediaPlayer = MediaPlayer.create(this, R.raw.selecttools);
mediaPlayer.start();
paintbrush1.setStrokeWidth(20f);
paintbrush1.setColor(Color.BLACK);
currentColor1(paintbrush1.getColor());
}
public void Clear1(View view){
MediaPlayer mediaPlayer = MediaPlayer.create(this, R.raw.selecttools);
mediaPlayer.start();
pathlist1.clear();
path1.reset();
colorList1.clear();
}
public static void currentColor1 (int c){
currentbrush1 = c;
path1 = new Path();
}
public static void currentsizebrush1(int c){
currentbrush1 = c;
path1 = new Path();
}
}
and this is the code for display which is the canvas this contains the pathlist and arrays for colors
import static com.example.artbit.EasyOne.paintbrush1;
import static com.example.artbit.EasyOne.path1;
import static com.example.artbit.EasyOne.brushsize1;
import android.graphics.Paint;
import android.graphics.Path;
public class display2 extends View {
public static MediaPlayer player;
public static ArrayList<Path> pathlist1 = new ArrayList<>();
public static ArrayList<Path> pathlist2 = new ArrayList<>();
public static ArrayList<Integer> brushList1 = new ArrayList<>();
public static ArrayList<Integer> colorList1 = new ArrayList<>();
public ViewGroup.LayoutParams params;
public static int currentbrush1 = Color.BLACK;
public display2(Context context) {
super(context);
init(context);
}
public display2(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}
public display2(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context){
paintbrush1.setAntiAlias(true);
paintbrush1.setColor(Color.BLACK);
paintbrush1.setStyle(Paint.Style.STROKE);
paintbrush1.setStrokeCap(Paint.Cap.ROUND);
paintbrush1.setStrokeJoin(Paint.Join.ROUND);
paintbrush1.setStrokeWidth(10f);
params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
path1.moveTo(x,y);
invalidate();
return true;
case MotionEvent.ACTION_MOVE:
path1.lineTo(x,y);
pathlist1.add(path1);
colorList1.add(currentbrush1);
brushList1.add(currentbrush1);
invalidate();
return true;
default:
return false;
}
}
#Override
protected void onDraw(android.graphics.Canvas canvas) {
for (int i=0; i<pathlist1.size(); i++){
paintbrush1.setColor(colorList1.get(i));
paintbrush1.setStrokeWidth(brushList1.get(i));
canvas.drawPath(pathlist1.get(i),paintbrush1);
invalidate();
}
}
}
I think I figured out the problem, the problem is in your onTouchEvent at
brushList1.add(currentbrush1);
You are adding to the ArrayList of brush's size the Color of the Path which is Black by default is -16777216 so when in draw you set the strokeWidth to a negative value it uses the Paint current value. So create a static int strokeWidth inside display2 and add to all your brush methods strokeWidth = //width number; like so
public void SmallBrush1(View view){
paintbrush1.setStrokeWidth(10f);
strokeWidth = 10; //ADD THIS
paintbrush1.setColor(Color.BLACK);
currentColor1(paintbrush1.getColor());
}
Do for all your brush methods
So change this
brushList1.add(currentbrush1);
to
brushList1.add(strokeWidth);
this should fix your problem
Hope that helps
Related
I'm new to Java and android development and I want to create this basic app, which consists of multiple CustomViews, where I could move different shapes drawn on canvas.
My idea is to have one class that handles MotionEvents and passes them to individual CustomViews.
My CustomView class:
public class CustomView extends View implements MoveDetector.OnMoveListener {
private MoveDetector mMoveDetector;
public CustomView(Context context) {
super(context);
}
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs);
}
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public CustomView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(attrs);
}
private void init(#Nullable AttributeSet set){
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.parseColor("#626696"));
}
#Override
public boolean onTouchEvent(MotionEvent event){
switch (event.getAction()){
case MotionEvent.ACTION_MOVE:
mMoveDetector = new MoveDetector(this);
mMoveDetector.onTouchEvent(event);
float cx = mMoveDetector.getCx();
float cy = mMoveDetector.getCy();
Toast.makeText(getContext(),"why u packin heat bro?"+Float.toString(cx)+" "+Float.toString(cy),Toast.LENGTH_SHORT).show();
Log.d("Moveee", "Move: " + Float.toString(cx)+" " + Float.toString(cy));
}
return super.onTouchEvent(event);
}
#Override
public void OnMove(MoveDetector moveDetector) {
}
}
My MoveDetector Class:
public class MoveDetector {
private float cx,cy, mCislo1,mCislo2;
public float getCx() {
return mCislo1;
}
public float getCy() {
return mCislo2;
}
private OnMoveListener mListener;
public MoveDetector(OnMoveListener listener){
mListener = listener;
}
public boolean onTouchEvent(MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_MOVE:
float x = event.getX();
float y = event.getY();
mCislo1 = cXX(x);
mCislo2 = cYY(y);
if (mListener != null) {
mListener.OnMove(this);
}
break;
}
return true;}
public static interface OnMoveListener {
public void OnMove(MoveDetector moveDetector);
}
public float cXX(float x){
cx = x;
return cx;
}
public float cYY(float y){
cy = y;
return cy;
}
}
It doesn't seem to be working and I can't point why.
I searched a solution for ages and couldn't find any.
So I'd be really thankful if someone could help me out.
P.S.: Sorry, if my code is messy: I'm still learning.
I want to achieve something like this.
but instead of that, I'm getting something like this.
I'm using invalidate to redraw my custom view. But it is creating another view everytime the sides of polygon is changed. Where am I going wrong?
Here is my code.
PolygonView.Java
public class PolygonView extends View {
public float polygonRadius;
public int polygonSides;
public int polygonColor;
private Paint paint;
private Path path;
public PolygonView(Context context) {
super(context);
init(null);
}
public PolygonView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public PolygonView(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs);
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public PolygonView(Context context, #Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(attrs);
}
private void init(AttributeSet attrs)
{
polygonColor = ContextCompat.getColor(getContext(),R.color.polygonColor);
polygonSides = 5;
if (attrs!=null){
TypedArray typedArray = getContext().getTheme().obtainStyledAttributes(attrs,R.styleable.PolygonView,0,0);
polygonColor = typedArray.getColor(R.styleable.PolygonView_polygon_color,polygonColor);
polygonRadius = typedArray.getDimension(R.styleable.PolygonView_polygon_radius,polygonRadius);
polygonSides = typedArray.getInteger(R.styleable.PolygonView_polygon_sides,polygonSides);
}
paint = new Paint();
paint.setColor(polygonColor);
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(5);
path = new Path();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
double angle = 2.0*Math.PI/polygonSides;
int cx = getWidth()/2;
int cy = getHeight()/2;
path.moveTo(
(float) (cx +polygonRadius*Math.cos(0.0)),
(float) (cy +polygonRadius*Math.sin(0.0))
);
for(int i=1;i<=polygonSides;i++){
path.lineTo(
(float) (cx + polygonRadius*Math.cos(angle*i)),
(float) (cy + polygonRadius*Math.sin(angle*i))
);
}
path.close();
canvas.drawPath(path,paint);
}
}
Fragment2.Java
public class Fragment2 extends Fragment {
public Fragment2() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_polygon, container, false);
final PolygonView polygonView = v.findViewById(R.id.polygonView);
SeekBar seekBarRadius = v.findViewById(R.id.seekBarRadius);
SeekBar seekBarSides = v.findViewById(R.id.seekBarSides);
seekBarSides.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
int p = progress/10;
if(p<1){
polygonView.polygonSides = 1;
}else if (p>10){
polygonView.polygonSides = 10;
}
else {
polygonView.polygonSides = p;
}
polygonView.invalidate();
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
return v;
}
}
You are always mutating your path but never reset it. Inside onDraw() method reset the path and only then apply new operations to it:
public void onDraw() {
path.reset();
...
}
I'm a beginner in android. I'm creating a simple surface view to draw a thread (draw rectangle), but it keeps getting error like this :
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.graphics.Canvas.drawColor(int)' on a null object reference
and this is my code :
myActivity.java :
public class myActivity extends AppCompatActivity {
mySurfaceView mysurfaceview;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ball);
//mysurfaceview = new mySurfaceView(this);
mysurfaceview = (mySurfaceView) findViewById(R.id.mySurfaceView);
mysurfaceview.RunThread();
}
mySurfaceview.java :
public class mySurfaceView extends SurfaceView implements SurfaceHolder.Callback {
public DrawThread DrawThread;
private Rect myrectangle;
private Paint myPaint;
int moveX = 0;
private void init() {
myrectangle = new Rect(150, 150, 700, 500);
myPaint = new Paint();
myPaint.setColor(Color.BLUE);
}
public mySurfaceView(Context context) {
super(context);
//init();
}
public mySurfaceView(Context context, AttributeSet attrs, int defStyle){ super(context, attrs, defStyle); }
public mySurfaceView(Context context, AttributeSet attrs) { super(context, attrs); }
public void onDrawSomething(Canvas canvas) {
canvas.drawColor(Color.BLACK);
canvas.drawRect(myrectangle, myPaint);
}
#Override
public void surfaceCreated(SurfaceHolder holder) { }
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { }
#Override
public void surfaceDestroyed(SurfaceHolder holder) { }
public void update(){
}
public void RunThread() {
init();
DrawThread = new DrawThread(getHolder(), this);
DrawThread.setRunning(true);
DrawThread.start();
}
public class DrawThread extends Thread {
//var definition
public boolean run = false;
private SurfaceHolder surfaceHolder;
mySurfaceView mysurfaceView;
public DrawThread(SurfaceHolder surfaceHolder, mySurfaceView mysurfaceView) {
this.surfaceHolder = surfaceHolder;
this.mysurfaceView = mysurfaceView;
}
public void setRunning(boolean run) {
this.run = run;
}
#Override
public void run() {
while(run)
{
//implement fps counter
Canvas canvas = null;
try {
canvas = surfaceHolder.lockCanvas();
synchronized (surfaceHolder) {
mysurfaceView.onDrawSomething(canvas);
//mysurfaceView.update();
}
} finally {
if(canvas != null)
{
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}
}
}
And this is my XML code to show surface view :
<com.example.firstapp_aurelia.mySurfaceView
android:id="#+id/mySurfaceView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Did I do anything wrong here? Thank you so much.
I didn't run you code but do not initial mySurfaceView twice
mysurfaceview = new mySurfaceView(this);
mysurfaceview = (mySurfaceView) findViewById(R.id.mySurfaceView);
I've tried extending LinearLayout instead of simple View for adding buttons and working children of View but I am still not getting any output. Conceptually I'm wrong somewhere.
public class TouchEventView extends LinearLayout {
private Paint paint = new Paint();
private Path path = new Path();
private ViewGroup viewGroup;
public TouchEventView(Context ctx) {
super(ctx);
//Button Code Starts Here
LinearLayout touch = new TouchEventView(ctx);
Button bt = new Button(ctx);
bt.setText("A Button");
bt.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT));
touch.addView(bt); //Button Not Working
paint.setAntiAlias(true);
paint.setColor(Color.BLACK);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(5f);
this.setBackgroundColor(Color.WHITE);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawPath(path,paint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float xPos = event.getX();
float yPos = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
path.moveTo(xPos,yPos);
return true;
case MotionEvent.ACTION_MOVE:
path.lineTo(xPos,yPos);
break;
case MotionEvent.ACTION_UP:
break;
default:
return false;
}
invalidate();
return true;
}
}
The issue is that you are creating a new TouchEventView and adding the Button to that View. Instead you should add the Button directly to the current View.
You should also implement the other constructors from LinearLayout if you want to be able to get any attributes from XML.
public class TouchEventView extends LinearLayout {
public TouchEventView(Context context) {
this(context, null);
}
public TouchEventView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TouchEventView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
Button button = new Button(getContext());
button.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
addView(button);
}
}
i have a problem with my Android Studio version 1.2.1.1. As mentioned in title my Preview for API 21/22 doesnt keep correct view sizes, however on phone the view looks just like it should look. Is there a way to solve this?
Link: https://screencloud.net/v/nrjv
I have extended class TextView, so it supports custom fonts:
public class FontTextView extends TextView{
public FontTextView(Context context){
super(context);
}
public FontTextView(Context context, AttributeSet attrs){
super(context, attrs);
readAttributes(context, attrs);
}
public FontTextView(Context context, AttributeSet attrs, int defStyleAttr){
super(context, attrs, defStyleAttr);
readAttributes(context, attrs);
}
private void readAttributes(Context context, AttributeSet attrs){
TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.FontTextView);
int fontIndex = attributes.getInt(R.styleable.FontTextView_customFont, 0);
this.setTypeface(TypefaceCreator.getTypeface(fontIndex));
attributes.recycle();
}
}
And i have class which builds these fonts while app starts:
public class TypefaceCreator {
public static final int HELVETICA_MEDIUM = 0;
public static final int HELVETICA_LIGHT = 1;
public static final int HELVETICA_ITALIC = 2;
public static final int HELVETICA_ROMAN = 3;
private static Typeface light;
private static Typeface italic;
private static Typeface roman;
private static Typeface medium;
private static TypefaceCreator creator;
private TypefaceCreator(Context context){
light = Typeface.createFromAsset(context.getAssets(),"HelveticaNeueLTPro-Lt.otf");
italic = Typeface.createFromAsset(context.getAssets(),"HelveticaNeueLTPro-It.otf");
roman = Typeface.createFromAsset(context.getAssets(),"HelveticaNeueLTPro-Roman.otf");
medium = Typeface.createFromAsset(context.getAssets(),"HelveticaNeueLTPro-Md.otf");
}
public static TypefaceCreator getInstance(Context context){
if(creator == null)
creator = new TypefaceCreator(context);
return creator;
}
public static Typeface getTypeface(int index){
switch(index) {
case HELVETICA_LIGHT:
return light;
case HELVETICA_ITALIC:
return italic;
case HELVETICA_ROMAN:
return roman;
default:
return medium;
}
}
}