I've defined a custom drawable shown below:
private class SquareDrawableView extends View {
private ShapeDrawable mDrawable;
public SquareDrawableView(int x, int y, int size, int color, Context context) {
super(context);
mDrawable = new ShapeDrawable(new RectShape());
mDrawable.getPaint().setColor(color);
mDrawable.setBounds(x, y, x + size, y + size);
}
public void setColor(int color) {
mDrawable.getPaint().setColor(color);
}
protected void onDraw(Canvas canvas) {
mDrawable.draw(canvas);
}
}
I'm trying to tile a number of these across a LinearLayout. Presently, when I run this code, I just get one square appearing in the "first" position of the LinearLayout. What am I doing wrong here?
top = (LinearLayout)findViewById(R.id.top);
SquareDrawableView[] topSquares = new SquareDrawableView[horizCount];
for(int i = 0; i < horizCount; ++i) {
topSquares[i] = new SquareDrawableView(i*SQUARE_SIZE,0,SQUARE_SIZE,BLUE,this);
top.addView(topSquares[i]);
}
Related
I wanna to do line number for children app
The line should look like the following
I think to use seekbar but I found it not possible as a range, not static also need to do an action when the user touches each number. so I ask for help or suggestion.
also has to do functionality of drawing an arc
the arc has to be drawn dynamically while the user moves his finger on numbers
also draw a rectangle when touching any number.
I'd like to ask for any advice or help in implementing something like that.
edit1: the line used to solve an equation as in the third image
You can use Custom View (Custom Drawing) which can help you in drawing the shaps check the link hope it helpscustom-views android-developers
There's probably a much better way to do this but here's what I came up with, hope its enough to point you in the right direction:
Activity:
public class DrawActivity extends AppCompatActivity {
float startPointX = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_draw);
MyDrawable drawing = new MyDrawable(this);
setContentView(drawing);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
MyDrawable drawing = new MyDrawable(this);
if (event.getY() > 1000) { // Click below line to reset
startPointX = 0;
} else if (startPointX == 0) { // Draw rectangle
startPointX = event.getX();
drawing = new MyDrawable(this, startPointX);
} else if (startPointX > 0) { // Draw arc
drawing = new MyDrawable(this, startPointX, event.getX());
}
setContentView(drawing);
return true;
}
}
Drawable:
public class MyDrawable extends View {
private Canvas mCanvas;
private Paint mRedPaint;
private Paint mGreenPaint;
private Paint mBluePaint;
float baseLine = 500;
float rectangleX;
float arcEnd;
public MyDrawable(Context context) {
super(context);
}
public MyDrawable(Context context, float startPoint) {
super(context);
rectangleX = startPoint;
}
public MyDrawable(Context context, float startPoint, float endPoint) {
super(context);
rectangleX = startPoint;
arcEnd = endPoint;
}
#Override
public void onDraw(Canvas canvas) {
mCanvas = canvas;
int width = 1000;
setupPaint();
canvas.drawLine(50, baseLine, width, baseLine, mBluePaint);
int mark = 50;
while(mark < width) {
canvas.drawLine(mark, baseLine-50, mark, baseLine+50, mGreenPaint);
mark += (width /10);
}
drawRectangle();
drawArc();
}
private void setupPaint() {
mRedPaint = new Paint();
mRedPaint.setARGB(255, 180, 0, 0);
mRedPaint.setStyle(Paint.Style.STROKE);
mRedPaint.setStrokeWidth(15);
mGreenPaint = new Paint();
mGreenPaint.setARGB(255, 0, 180, 0);
mGreenPaint.setStrokeWidth(15);
mBluePaint = new Paint();
mBluePaint.setARGB(255, 0, 0, 180);
mBluePaint.setStrokeWidth(30);
}
public void drawRectangle() {
if ( rectangleX > 0) {
mCanvas.drawRect(rectangleX - 25, baseLine-50, rectangleX + 25, baseLine+50, mRedPaint);
}
}
public void drawArc() {
if (arcEnd != 0 && arcEnd < rectangleX) {
mCanvas.drawArc(arcEnd, baseLine-200, rectangleX, baseLine, 0, -180, false, mRedPaint);
} else if (arcEnd != 0 && arcEnd > rectangleX) {
mCanvas.drawArc(rectangleX, baseLine-200, arcEnd, baseLine, 0, -180, false, mRedPaint);
}
}
}
I have to make a gradient color effect in the view that generated dynamically according to the scenario and also the view would be of any shape (diagonal or square)
As shown in image, gradient effect could be in any shape.
Also, if I create custom view for every possible case and play with Visibility, then how I will manage these views to fit perfectly on every device screen size?
Just need a small help to start.
Thanks in advance.
I have solved the issue using this approach.
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new CustomView(this));
}
}
and now create a CustomView class
public class CustomView extends View {
Rect rect;
private Rect rectangle;
private Paint paint;
public CustomView(Context context) {
super(context);
int x = 50;
int y = 50;
int sideLength = 200;
int sideLength1 = 100;
rectangle = new Rect(x, y, sideLength, sideLength1);
paint = new Paint();
paint.setColor(Color.GRAY);
}
#Override
protected void onDraw(Canvas canvas) {
int width = this.getMeasuredWidth();
int height = this.getMeasuredHeight();
BitmapShader shader;
//shader = new BitmapShader(header, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
//paint.setShader(shader);
Path path = new Path();
path.moveTo(40,40);
path.lineTo(5,height/2);
path.lineTo(width/2,height/4);
path.lineTo(width/2,0);
canvas.drawPath(path,paint);
}
I'm using RelativeLayout to absolutely position some standard views (like TextView).
What I'd like to do is to draw a custom line on this RelativeLayout's Canvas using Canvas.drawLine that is drawn behind all its other subviews.
These other subviews are added with explicitely defining RelativeLayout.LayoutParams, but I'd like to leave the decision of where to paint itself to my custom line.
I tried wrapping this line in a CustomView with overloaded View.onDraw(Canvas canvas) method and simply adding the view without specifying any LayoutParams, so:
public class CustomView extends View {
public CustomView(Context context, int x0, int y0, int x1, int y1) {
super(context);
setClickable(false);
setBackgroundColor(Color.TRANSPARENT);
}
public void onDraw(Canvas canvas) {
Log.i("myapp", "i'm not called! :(")
Paint p = new Paint();
p.setColor(Color.BLACK);
canvas.drawLine(x0, y0, x1, y1, p);
}
}
And usage:
CustomView v = new CustomView(MyActivity.this, 0, 0, 100, 100);
relativeLayout.addView(v);
... but this onDraw method is never called.
Is there a way to make this work?
Edit: works if I substitute:
relativeLayout.addView(v)
with
relativeLayout.addView(v,
new RelativeLayout.LayoutParams(SOME_WIDTH, SOME_HEIGHT));
The point is, I know neither SOME_WIDTH, nor SOME-HEIGHT at that point.
try this custom RelativeLayout:
class RL extends RelativeLayout {
private Paint mPaint;
public RL(Context context) {
super(context);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStrokeWidth(5);
mPaint.setColor(0xffffffff);
}
#Override
protected void dispatchDraw(Canvas canvas) {
int cnt = getChildCount();
for (int i = 0; i < cnt; i++) {
View child = getChildAt(i);
int l = child.getLeft();
int t = child.getTop();
int r = child.getRight();
int b = child.getBottom();
if (i % 2 == 0) {
canvas.drawLine(l, t, r, b, mPaint);
} else {
canvas.drawLine(l, b, r, t, mPaint);
}
}
super.dispatchDraw(canvas);
}
}
and test it ba adding the following in onCreate() method:
RelativeLayout rl = new RL(this);
TextView tv;
List<String> list = Arrays.asList("one", " two ", "three", " four ", "fife");
int i = 0;
for (String string : list) {
int id = 1000 + i;
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
if (i != 0) {
params.addRule(RL.BELOW, id - 1);
}
tv = new TextView(this);
tv.setTextSize(48);
tv.setTextColor(0xffff0000);
tv.setText(string);
rl.addView(tv, params);
tv.setId(id);
i++;
}
setContentView(rl);
So.
I ended up creating a CustomController which has some methods to calculate position/size and using this controller when creating RelativeLayout.LayoutParams for each CustomView(context, controller).
I guess you cannot have a subview in a RelativeLayout without specifying its RelativeLayout.LayoutParams.
Easiest way is to call the super.draw(Canvas) method after you finished your background in the onDraw() method.
That will cause it to draw the children last.
Is there a method to draw text with in a specified rectangle?
I am drawing directly to a canvas(ImageView) using
canvas.drawText(text,x,y,paint)
But this drew the entire text in a single line. I want to wrap the text with in the specified (x,y) ,(x1,y1) limit. I don't want to use textviews or any other views.
I just want to draw the text over an image.
Is there any method to do this?
Thanks in Advance
Firstly you have to determine the text size. The width of each character could be get by getTextWidths(), the height is same with text size. Try to estimate a initial text size, and use the height and width of text to adjust the final value.
Secondly you need to break lines. Paint.getTextWidths() or Paint.breakText() can all achieve this target.
Edit: add the code example.
public static class RectTextView extends View {
private int mWidth = 200;
private int mHeight = 100;
private String mText = "Hello world. Don't you know why, why you and I.";
private Paint mPaint;
private List<Integer> mTextBreakPoints;
public RectTextView(Context context) {
this(context, null);
}
public RectTextView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
mPaint.setColor(Color.WHITE);
mPaint.setAntiAlias(true);
setSuitableTextSize();
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(mWidth, mHeight);
}
#Override
protected void onDraw(Canvas canvas) {
int start = 0;
int x = 0;
int y = 0;
for (int point : mTextBreakPoints) {
y += mPaint.getTextSize();
canvas.drawText(mText, start, point, x, y, mPaint);
start = point;
}
}
private void setSuitableTextSize() {
int textSize = getEstimateTextSize();
for (; textSize > 0; textSize--) {
if (isTextSizeSuitable(textSize))
return;
}
}
private boolean isTextSizeSuitable(int size) {
mTextBreakPoints = new ArrayList<Integer>();
mPaint.setTextSize(size);
int start = 0;
int end = mText.length();
while (start < end) {
int len = mPaint.breakText(mText, start, end, true, mWidth,
null);
start += len;
mTextBreakPoints.add(start);
}
return mTextBreakPoints.size() * size < mHeight;
}
private int getEstimateTextSize() {
return (int) Math.sqrt(mWidth * mHeight / mText.length() * 2);
}
}
I am trying to apply a scale animation to a rectangle, using code not xml. I want to make the rectangle grow taller, pretty simple.
RectDrawableView - creates a RectShape ShapeDrawable
public class RectDrawableView extends View {
Paint paint;
public RectDrawableView(Context context) {
super(context);
paint = new Paint();
paint.setColor(Color.parseColor("#aacfcce4"));
paint.setStyle(Paint.Style.FILL);
}
protected void onDraw(Canvas canvas) {
int x = 35;
int y = 250;
int width = 50;
int height = 300;
ShapeDrawable shapeDrawable = new ShapeDrawable(new RectShape());
Rect rect = new Rect(x, y, x+width, y+height);
shapeDrawable.setBounds(rect);
shapeDrawable.getPaint().set(paint);
shapeDrawable.draw(canvas);
}
}
Activity: - Creates a new RectDrawableView and adds to layout. OnResume an animation is triggered, which should make the rectangle grow taller.
public class RectActivity extends Activity {
final String TAG = "RectActivity";
TextView rect1;
RectDrawableView rectView;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.basic);
LinearLayout linear = (LinearLayout) findViewById(R.id.basicLayout);
rectView = new RectDrawableView(this);
linear.addView(rectView);
}
#Override
public void onResume() {
super.onResume();
RunAnimations();
}
private void RunAnimations() {
Animation rectAnim1 = new ScaleAnimation(1, 1, 1, 1.3f, ScaleAnimation.RELATIVE_TO_SELF, 0,
ScaleAnimation.RELATIVE_TO_SELF, 1);
rectAnim1.setFillBefore(false);
rectAnim1.setFillAfter(true);
rectAnim1.setStartOffset(500);
rectAnim1.setDuration(500);
rectView.startAnimation(rectAnim1);
}
}
basic.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/basicLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
</LinearLayout>
Result: The rect is growing taller, good, but the location of the rect is also changing, bad. The whole rectangle is being positioned higher up the screen.
When I use this exact same animation code, but apply it to a TextView instead of a ShapeDrawable, all is good.
I've trawled through all the related articles on SO, but I'm still struggling with this one. Any help would be appreciated, thanks.
Complete code, i had changed the height of the rectangle.
public class RectActivity extends Activity {
final String TAG = "RectActivity";
TextView rect1;
RectDrawableView rectView;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.basic);
LinearLayout linear = (LinearLayout) findViewById(R.id.rectangle);
rectView = new RectDrawableView(this);
linear.addView(rectView);
Button sbutton = (Button)findViewById(R.id.sbutton);
sbutton.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
RectActivity.this.RunAnimations();
}
});
Button tbutton = (Button)findViewById(R.id.tbutton);
tbutton.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
RectActivity.this.runTranslateAnimation();
}
});
}
#Override
public void onResume() {
super.onResume();
RunAnimations();
}
private void RunAnimations() {
Animation rectAnim1 = new ScaleAnimation(1, 1, 1, 1.3f,
ScaleAnimation.RELATIVE_TO_SELF, 0,
ScaleAnimation.ABSOLUTE, 250);
rectAnim1.setFillBefore(false);
rectAnim1.setFillAfter(true);
rectAnim1.setStartOffset(500);
rectAnim1.setDuration(500);
rectView.startAnimation(rectAnim1);
}
private void runTranslateAnimation() {
float x = rectView.getX();
float y = rectView.getY();
TranslateAnimation trans = new TranslateAnimation(0, 0, 0, (90));
trans.setFillAfter(true);
trans.setStartOffset(500);
trans.setDuration(500);
rectView.startAnimation(trans);
}
}
public class RectDrawableView extends View {
Paint paint;
Rect rect;
public RectDrawableView(Context context) {
super(context);
paint = new Paint();
paint.setColor(Color.parseColor("#aacfcce4"));
paint.setStyle(Paint.Style.FILL);
}
protected void onDraw(Canvas canvas) {
int x = 50;
int y = 150;
int width = 50;
int height = 100;
ShapeDrawable shapeDrawable = new ShapeDrawable(new RectShape());
rect = new Rect(x, y, x+width, y+height);
shapeDrawable.setBounds(rect);
shapeDrawable.getPaint().set(paint);
shapeDrawable.draw(canvas);
}
}
Try this code. Keep the pivotYType as ABSOLUTE with value 550 ( y + height )
Animation rectAnim1 = new ScaleAnimation(1, 1, 1, 1.3f,
ScaleAnimation.RELATIVE_TO_SELF, 0,
ScaleAnimation.ABSOLUTE, 550);