How to place a TextView on a CustomView programatically? - android

In my application I design a custom view, and here is the code
public class Tunnel extends View implements View.OnTouchListener {
Paint paint = new Paint();
public Tunnel(Context context) {
super(context);
setOnTouchListener(this);
}
#Override
public void onDraw(Canvas canvas) {
paint.setColor(Color.RED);
for (int x = 0; x < canvas.getWidth(); x++) {
canvas.drawLine(x, (float) upperBound(x), x, (float) lowerBound(x), paint);
}
setBackgroundColor(Color.BLACK);
}
private double upperBound(double x) {
return 50 * Math.sin(x / 50) + 400;
}
private double lowerBound(double x) {
return 50 * Math.sin(x / 50) + 600;
}
#Override
public boolean onTouch(View v, MotionEvent event) {
return false;
}
}
And it looks like this
Now what I need to do, is add a custom TextView on this view, which will show some text. As far as i realise, my constructor should look like this
public Tunnel(Context context) {
super(context);
setOnTouchListener(this);
TextView tv = new TextView(getContext());
tv.setX(200);
tv.setY(200);
//todo show the textView
}
But i don't know what to write next. How can i apply the textView to my view?
Thanks in advance

try
public Tunnel(Context context) {
super(context);
setOnTouchListener(this);
TextView tv = new TextView(getContext());
tv.setX(200);
tv.setY(200);
tv.setText("Text");
TheCustomView.addView(tv);
}

I inherited my custom view from a linear layout, set it to do the onDraw method, and it worked for me
public class Tunnel extends LinearLayout implements View.OnTouchListener {
Paint paint = new Paint();
TextView tv;
public Tunnel(Context context) {
super(context);
setOnTouchListener(this);
setWillNotDraw(false);
tv = new TextView(getContext());
tv.setX(450);
tv.setY(800);
tv.setTextSize(20f);
tv.setTextColor(Color.WHITE);
addView(tv);
}
#Override
public void onDraw(Canvas canvas) {
paint.setColor(Color.RED);
for (int x = 0; x < canvas.getWidth(); x++) {
canvas.drawLine(x, (float) upperBound(x), x, (float) lowerBound(x), paint);
}
setBackgroundColor(Color.BLACK);
}
private double upperBound(double x) {
return 50 * Math.sin(x / 50) + 400;
}
private double lowerBound(double x) {
return 50 * Math.sin(x / 50) + 600;
}
#Override
public boolean onTouch(View v, MotionEvent event) {
return false;
}
}

Related

Android: Draw random circles on screen on touch

I'm working on a project that requires me to draw a circle at a random location on the screen when the user touches the screen. When the touch event occurs it also needs to remove the last circle I drew, so that there can only be one circle on the screen at one time.
I have a class Circle, that I use to create a circle:
public class Circle extends View {
private final float x;
private final float y;
private final int r;
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
public Circle(Context context, float x, float y, int r) {
super(context);
mPaint.setColor(0x000000);
this.x = x;
this.y = y;
this.r = r;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(Color.RED);
canvas.drawCircle(x, y, r, mPaint);
}
}
This is the activity from which a new Circle is created. It will also monitor touch events. Right now it is drawing a circle in the upper left hand corner of the screen, but that code will need to be moved into the onTouch method. I will likely calculate the random number using Random.
public class FingerTappingActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_finger_tapping);
LinearLayout circle = (LinearLayout) findViewById(R.id.lt);
View circleView = new Circle(this, 300, 300, 150);
circleView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
circle.addView(circleView);
circle.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
}
}
I have never worked with touch events before such as these and have no idea how to go about this. Some tips would be greatly appreciated.
Do some thing like this ,
public class DrawCircles extends View {
private float x = 100;
private float y = 100;
private int r = 50;
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(Color.RED);
canvas.drawCircle(x, y, r, mPaint);
}
public DrawCircles(Context context) {
super(context);
init();
}
public DrawCircles(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public DrawCircles(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
void init() {
mPaint.setColor(0x000000);
// logic for random call here;
}
Random random = new Random();
void generateRandom() {
int minRadius = 100;
int w = getWidth();
int h = getHeight();
this.x = random.nextInt(w);
this.y = random.nextInt(h);
this.r = minRadius + random.nextInt(100);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
generateRandom();
invalidate();
return super.onTouchEvent(event);
}
}
This view will draw random circles inside the view . make some adjustments for generating x & y coordinates . add this view to xml then it will work.

how to make vertical progressbar with divider

I want to make vertical progress bar with dividers on it. however , i am unable to do so.
This code works fine for horizontal progress bar but when i want to make it work like vertical progress bar it doesn't work.
Any help appreciated.
class ProgressDrawable extends Drawable {
private static final int NUM_RECTS = 10;
Paint mPaint = new Paint();
#Override
protected boolean onLevelChange(int level) {
invalidateSelf();
return true;
}
#Override
public void draw(Canvas canvas) {
int level = getLevel();
Rect b = getBounds();
float height = b.height();
for (int i = 0; i < NUM_RECTS; i++) {
float bottom = height * i / NUM_RECTS;
float top = bottom + 0.9f * height / NUM_RECTS;
mPaint.setColor((i + 1) * 10000 / NUM_RECTS <= level? 0xff888888 : 0xffbbbbbb);
// canvas.drawRect(left, b.top, right, b.bottom, mPaint);
//canvas.drawRect(left, b.top, right, b.bottom, mPaint);
canvas.drawRect(bottom, b.bottom, top, b.top, mPaint);
}
}
#Override
public void setAlpha(int alpha) {
}
#Override
public void setColorFilter(ColorFilter cf) {
}
#Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
}
I know its late , but if someone want looking for it ,you can see here
private static final int NUM_RECTS = 10;
Paint mPaint = new Paint();
#Override
public void draw(Canvas canvas) {
// TODO Auto-generated method stub
int level = getLevel();// It will give the level of progress(0 to 10,000)
Rect b = getBounds();
float height = b.height();
float width=b.width();
float x=40;
float y=0;
for (int i =0; i<NUM_RECTS; i++) {
if((i+1)*10000/NUM_RECTS>level)
{
mPaint.setColor(Color.GRAY);
}else{
mPaint.setColor(Color.GREEN);
}
canvas.drawRect(0,height-x,width,height-y, mPaint);
//canvas.drawCircle(width/2,height-y,30, mPaint);
x=x+50;
y=y+50;
}
}
#Override
public void setAlpha(int alpha) {
}
#Override
public void setColorFilter(ColorFilter colorFilter) {
}
#Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
#Override
protected boolean onLevelChange(int level) {
invalidateSelf();
return true;
}
}

custom view can be clicked

I want to make my custom view be clicked.And now I do not know which is wrong,when I click it
,it happens nothing.Thanks in advance.This view is that I use canvas to draw a ring,and I want the inside of the ring can be clicked.
public class CircleProgressBar extends View{
OnClickListener progressButton;
private int hour;
private int maxProgress = 24;
private int progress;
int progress1;
private int progressStrokeWidth = 32;
RectF oval;
Paint paint;
Paint paint1;
public CircleProgressBar(Context context, AttributeSet attrs) {
super(context, attrs);
oval = new RectF();
paint = new Paint();
paint1 = new Paint();
}
#Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
Calendar c=Calendar.getInstance();
hour = c.get(Calendar.HOUR_OF_DAY);
progress = hour;
int width = this.getWidth();
int height = this.getHeight();
if(width != height){
int min = Math.min(width, height);
width = min;
height = min;
}
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setColor(Color.LTGRAY);
canvas.drawColor(Color.TRANSPARENT);
paint.setStrokeWidth(15);
paint.setStyle(Style.STROKE);
oval.left = progressStrokeWidth / 2; // 左上角x
oval.top = progressStrokeWidth / 2; // 左上角y
oval.right =height - progressStrokeWidth / 2; // 左下角x
oval.bottom = height - progressStrokeWidth / 2; // 右下角y
canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG));
canvas.drawArc(oval, -90, 360, false, paint);
paint.setColor(Color.rgb(0x57, 0x87, 0xb6));
paint.setStrokeCap(Paint.Cap.ROUND);
if(progress == 9){
canvas.drawArc(oval, -90, 134, false, paint);
}else{
canvas.drawArc(oval, -90, (long)(((float) progress / maxProgress) * 360), false, paint);
}
paint.setColor(Color.CYAN);
paint.setAntiAlias(true);
canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG));
canvas.drawArc(oval, -90, 135+0.5f, false, paint);
paint.setStrokeWidth(15);
String text = (long)(((float) progress / maxProgress) * 100) + "%";
int textHeight = height / 4;
paint.setTextSize(textHeight);
int textWidth = (int) paint.measureText(text, 0, text.length());
paint.setStyle(Style.FILL);
canvas.drawText(text, width / 2 - textWidth / 2, height / 2 +textHeight/2, paint);
}
public int getMaxProgress() {
return maxProgress;
}
public void setMaxProgress(int maxProgress) {
this.maxProgress = maxProgress;
}
public void setProgress(int progress) {
this.progress = progress;
this.invalidate();
}
public void setProgressNotInUiThread(int progress) {
this.progress = progress;
this.postInvalidate();
}
#Override
public boolean onTouchEvent(MotionEvent event){
if(event.getAction() == MotionEvent.ACTION_DOWN){
}
return true;
}
This is my main activity.
public class MainActivity extends Activity{
Context context;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.circle_fit);
CircleProgressBar progressBar = (CircleProgressBar) findViewById(R.id.circleProgressbar);
progressBar.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
Toast.makeText(MainActivity.this, "hello", Toast.LENGTH_SHORT).show();
}
});
here is my xml
<com.example.circlefit.CircleProgressBar
android:id="#+id/circleProgressbar"
android:layout_width="200dp"
android:layout_height="200dp" />
Remove the touch listener in your custom class. It is ovveriding the click functionality :-
/
/Remove this piece of code from your class and it will work just fine
#Override
public boolean onTouchEvent(MotionEvent event){
if(event.getAction() == MotionEvent.ACTION_DOWN){
}
return true;
}
Add this in your XML:
android:clickable="true"
android:focusable="true"
try like this:
private OnClickListener clickListener;
private boolean isMoved;
#Override
public void setOnClickListener(OnClickListener l) {
this.clickListener = l;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
isMoved = false;
if (isValidtouchAndIsInsideCircle(event)) {
return true;
} else {
return false;
}
}
if (event.getAction() == MotionEvent.ACTION_MOVE) {
isMoved = true;
}
if (event.getAction() == MotionEvent.ACTION_UP) {
if (clickListener != null && !isMoved) {
clickListener.onClick(this);
}
isMoved = false;
}
return false;
}
private boolean isValidtouchAndIsInsideCircle(MotionEvent event) {
int xPoint = (int) event.getX();
int yPoint = (int) event.getY();
// here validate the x and y points with your circle coordinates if it
// is in circle return true or else return false
return false;
}

android-update line between two rotating rectangles

after i draw line between 2 fixed points on two different rectangles i need to rotate them.The problem is that my line is not updated, it stays on the same x1,y1 x2,y2. How to make line to follow this rectangle?
If any of you have any example code or something that can help, it would be great!
Thanks!
I dont think that i will need OnValidateUpdate tho solve this.
This is my example code to demonstrate this problem:
Object that i want to draw:
public class Object {
private int xPos;
private int yPos;
private int width;
private int height;
float xDistance = 0f;
float yDistance = 0f;
double angleToTurn = 0.0;
Matrix matrix = new Matrix();
private Rect rect;
private Paint paint;
private Point point;
Paint p = null;
public Object(int xPos, int yPos){
this.xPos = xPos;
this.yPos = yPos;
this.width = 300;
this.height = 100;
matrix = new Matrix();
rect = new Rect(xPos,yPos,xPos + width,yPos + height);
paint = new Paint();
paint.setStyle(Style.FILL);
paint.setColor(Color.BLUE);
p = new Paint();
p.setStyle(Style.FILL);
p.setStrokeWidth(15);
p.setColor(Color.BLACK);
point = new Point(this.getxPos(), this.getyPos()+this.getHeight());
}
public void rotate(float xEvent, float yEvent){
xDistance = xEvent - this.xPos;
yDistance = yEvent - this.yPos;
int angleToTurn = ((int)Math.toDegrees(Math.atan2(yDistance, xDistance)));
matrix.setRotate((int)(angleToTurn),xPos,yPos + height/2);
}
public void draw(Canvas c){
c.save();
c.setMatrix(matrix);
c.drawRect(rect, paint);
c.drawPoint(point.x,point.y,p);
c.restore();
}
public Point getPoint() {
return point;
}
public void setPoint(Point point) {
this.point = point;
}
public Matrix getMatrix() {
return matrix;
}
public void setMatrix(Matrix matrix) {
this.matrix = matrix;
}
public int getxPos() {
return xPos;
}
public void setxPos(int xPos) {
this.xPos = xPos;
}
public int getyPos() {
return yPos;
}
public void setyPos(int yPos) {
this.yPos = yPos;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
GameView class where i draw 2 rects:
public class GameView extends SurfaceView implements SurfaceHolder.Callback{
private SurfaceHolder surfaceHolder;
private GameloopThread gameloopThread;
float downx,downy,upx,upy;
private Object object,object1;
Line line;
public GameView(Context context) {
super(context);
gameloopThread = new GameloopThread(this);
surfaceHolder = getHolder();
surfaceHolder.addCallback(this);
object = new Object(500,500);
object1 = new Object(800,700);
line = new Line(object.getPoint(),object1.getPoint());
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
Canvas canvas = surfaceHolder.lockCanvas();
onDraw(canvas);
surfaceHolder.unlockCanvasAndPost(canvas);
gameloopThread.setRunning(true);
gameloopThread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
gameloopThread.setRunning(false);
while(retry){
try {
gameloopThread.join();
retry=false;
}catch(InterruptedException e){
}
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {
}
#SuppressLint("ClickableViewAccessibility")
#Override
public boolean onTouchEvent( MotionEvent event) {
float x = 0f,y=0f;
if(event.getAction() == MotionEvent.ACTION_DOWN){
downx = event.getX();
downy = event.getY();
}
if (event.getAction() == MotionEvent.ACTION_MOVE) {
x = event.getX();
y = event.getY();
object.rotate(x, y);
object1.rotate(x, y);
}
if (event.getAction() == MotionEvent.ACTION_UP) {
}
return true;
}
#Override
public void onDraw(Canvas canvas){
super.onDraw(canvas);
canvas.drawColor(Color.LTGRAY);
if(object != null)
object.draw(canvas);
if(object1 != null)
object1.draw(canvas);
if(line != null){
line._drawLine(canvas);
}
}
}
Line class that should connect two rectangles (i made class for it but it is not needed)
public class Line {
private Point point1,point2;
private Paint p;
Matrix m;
public Line(Point p1,Point p2){
this.point1 = p1;
this.point2 = p2;
p = new Paint();
p.setStyle(Style.FILL);
p.setColor(Color.RED);
m = new Matrix();
}
public void _drawLine(Canvas c){
c.setMatrix(m);
c.save();
c.drawLine(point1.x, point1.y, point2.x, point2.y, p);
c.restore();
}
public Matrix getMatrix(){
return m;
}
}
I would like to use Matrix object if possible to achieve that.There is also MainActivity and Thread class but I dont post them because thay are not relevant to this problem.
You can use ValueAnimator to animate the rectangles. On each
onAnimationUpdate(ValueAnimator animation)
you can invalidate or re-draw the line with the new position.
I found the solution I can just use Matrix.mapPoints, save them and just redraw line !

Gesture Detector with onDraw() called multiple times

I am using GestureDetector to identify the touch.I have two Relative layoutsof same layout size.I am trying to draw an image A on one layout and move an image B(created using onDraw) on another layout.While I move my image B I am using GestureDetector to identify the touch.When I move my image B, image A(view) onDraw() method is called multiple times. Please help me to avoid calling onDraw() multiple times.Here is my code
public class TouchExampleActivity extends Activity {
RelativeLayout r1;
RelativeLayout r2;
Context context;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
context = TouchExampleActivity.this;
r1 = (RelativeLayout) findViewById(R.id.r1);
r2 = (RelativeLayout) findViewById(R.id.r2);
TouchExampleView view = new TouchExampleView(this);
DrawCircle drawCircle = new DrawCircle(context);
r1.addView(view);
r2.addView(drawCircle);
}
class DrawCircle extends View {
Paint p;
public DrawCircle(Context context) {
super(context);
// TODO Auto-generated constructor stub
p = new Paint();
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
Log.v("Touch", "Called Draw Circle");
p.setColor(Color.BLUE);
canvas.drawCircle(60, 50, 50, p);
}
}
}
TouchExampleView.java
public class TouchExampleView extends View {
private Drawable mIcon;
private float mPosX;
private float mPosY;
static boolean fStartDrag = false;
static boolean fDrag = false;
private float ypos = 40;
private float xpos = 30;
public static float sx, sy;
private VersionedGestureDetector mDetector;
private float mScaleFactor = 1.f;
public TouchExampleView(Context context) {
this(context, null, 0);
}
public TouchExampleView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TouchExampleView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mIcon = context.getResources().getDrawable(R.drawable.icon);
mIcon.setBounds(0, 0, mIcon.getIntrinsicWidth(), mIcon.getIntrinsicHeight());
mDetector = VersionedGestureDetector.newInstance(context, new GestureCallback());
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
mDetector.onTouchEvent(ev);
return true;
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setColor(Color.RED);
paint.setStrokeWidth(5);
canvas.save();
canvas.translate(mPosX, 0);
canvas.scale(mScaleFactor, mScaleFactor);
canvas.drawRect(0, 0, 30, 30, paint);
canvas.restore();
}
private class GestureCallback implements VersionedGestureDetector.OnGestureListener {
public void onDrag(float dx, float dy) {
if ((dx == -1) && (dy == -1)) {
fStartDrag = true;
fDrag = false;
}
else if (fStartDrag) {
if (dy >= mPosY && dy <= ypos + mPosY && dx >= mPosX && dx <= mPosX + xpos) {
fDrag = true;
fStartDrag = false;
}
} else if (fDrag) {
System.out.println("fDrag");
if (mPosX < 3)
mPosX = 3;
else if (mPosX > 400)
mPosX = 400;
else
mPosX = dx;
// mPosY = dy;
postInvalidate();
}
}
public void onScale(float scaleFactor) {
mScaleFactor *= scaleFactor;
mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f));
postInvalidate();
}
}
}
My sample xml
<RelativeLayout
android1:id="#+id/r1"
android1:layout_width="620dip"
android1:layout_height="320dip"
android1:layout_alignParentBottom="true"
android1:layout_alignParentLeft="true"
android1:layout_marginBottom="94dp" >
</RelativeLayout>
<RelativeLayout
android1:id="#+id/r2"
android1:layout_width="620dip"
android1:layout_height="320dip"
android1:layout_alignParentBottom="true"
android1:layout_alignParentLeft="true"
android1:layout_marginBottom="94dp" >
</RelativeLayout>
If I use two relative layouts of different size and position then it works fine, onDraw() is not called multiple times
After trying so much I found this answer to my question.setDrawingCacheEnabled(true) prevents calling onDraw() multiple times.Its working for me.I hope I am going right.
View circleView;
r2 = (RelativeLayout) findViewById(R.id.r2);
circleView= r2;
circleView.setDrawingCacheEnabled(true);

Categories

Resources