How to draw a dynamic drawing over a layout - android

I am trying to make a thermometer. For this I have an image of a thermometer(a png file) which i have inserted
into the layout using ImageView. Now I want to draw a line over this image to show the effect of temperature reading.
Here is my code.
main.xml
<AbsoluteLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ImageView
</ImageView>
<com.focusone.Android.DrawExample.CustomDrawableView
android:id="#+id/custom_drawable_view"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
height='100'
/>
</AbsoluteLayout>
DrawExample.java
package com.focusone.Android.DrawExample;
public class DrawExample extends Activity {
/** Called when the activity is first created. */
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
CustomDrawableView.java
public class CustomDrawableView extends View {
private ShapeDrawable mDrawable;
public CustomDrawableView(Context v,AttributeSet as){
super(v,as);
drawShape(as);
}
public void drawShape(AttributeSet ast) {
int x =45; int y=15 ; int width=5; int height=0 ;
height= Integer.parseInt(ast.getAttributeValue(null, "height"));
mDrawable = new ShapeDrawable(new RectShape());
mDrawable.getPaint().setColor(0xff74AC23);
mDrawable.setBounds(x, y, x + width, y + height);
}
protected void onDraw(Canvas canvas) {
mDrawable.draw(canvas);
}
}
Now I can draw a line on top of the thermometer image using this program.
But how do i change the height of line during runtime.
Since height=100 is written in the xml file I don't know how I can change it.
Please somebody help me.

First I think you don't need to pass attributes in drawShape(AttributeSet ast) but just height in your constructor CustomDrawableView(). Then as Chris said you should have another method in the custom view like
public void setTemperature(int tmp){
drawShape(tmp);
invalidate(); //this will call onDraw()
}
In your main activity make a reference to your custom view so you can call its public methods
CustomDrawableView temperatureView =
(CustomDrawableView) findViewById(R.id.custom_drawable_view);
temperatureView.setTemperature(50);

You can:
Make "height" a member of your CustomDrawableView
Then create a method setHeight(int height) where you change the value of height.
Then in your activity use (CustomDrawableView)findViewById(R.id.custom_drawable_view) to get a reference to your viewObject.
Then change the value as you like with calling setHeight(x)
hope that helps

Related

How can I pass an int to my onDraw in Android? Whats wrong in my code?

in my example project :ondraw need an int to drawing from main activity, when initialize the parameter to 1 in mainActivity, its not draw anything,
//class MyView extends View
private int parameter=0;//if i change to 1 it will draw,
//but i want set it from main Activity
public void setParameter(int param)
{
this.parameter=param;
invalidate();
Log.i("tag9", this.parameter+" setParameter");
}
#Override
protected void onDraw(Canvas canvas) {
Log.i("tag9",parameter + " ondraw");
if(this.parameter==0){
return;}
//Drawing code ...
}
//in MainActivity:
MyView myView = new MyView(this);
myView.setParameter(1);
//Xml code:
<RelativeLayout ...>
<view
android:layout_width="wrap_content"
android:layout_height="wrap_content"
class="(packagename).MyView"
android:id="#+id/view"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="138dp"/>
</RelativeLayout>
//DDMS
1 setparameter
0 ondraw // its shouldnt be 0;
thnx to Gabe Sechan ,
You're creating it via new. That creates a new view not in any layout. If you want to reference a view set in xml, use findViewById – Gabe Sechan
MyView myView = (MyView)this.findViewById(R.id.view);
myView.setParameter(1);

dynamic xml layout rotation

I have two buttons on my main activity and when pressed I want to call the exact same activity exept that on one the layout is rotated 180 degrees. Is there any way to do this (like rotate based on an extra passed from main activity) do I really need to create two different activities with practically the same code in their respective java file?
EDIT: when I say exact same activity I don't mean the same as main. It's just the same for those two buttons...
I think i found a solution for you. Use a custom reverse view as a wraper to reverse the whole layout.
Try to run the sample code below.
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
int layoutId = R.layout.main;
View content = getLayoutInflater().inflate(layoutId, null);
ReverseView wraper = new ReverseView(this);
wraper.addView(content);
setContentView(wraper);
}
public class ReverseView extends FrameLayout {
public ReverseView(Context context) {
super(context);
}
#Override
protected void dispatchDraw(Canvas canvas) {
canvas.save();
int px = getWidth() / 2;
int py = getHeight() / 2;
canvas.rotate(180, px, py);
super.dispatchDraw(canvas);
canvas.restore();
}
}
}
You can change the orientation in your activity by adding the following code.
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
And you can also create a new layout xml in layout-land/, and when your activity enter the landscape mode, it will try to load the different layout.

Drawing vertical lines in android

i try to draw vertical lines in android.
DrawView drawView;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
drawView = new DrawView(this);
setContentView(drawView);
}
public class DrawView extends View {
Paint paint = new Paint();
public DrawView(Context context) {
super(context);
paint.setColor(Color.RED);
}
#Override
public void onDraw(Canvas canvas) {
canvas.drawLine(0, 100, 0, 0, paint);
}
}
What this draw just one line. What i want to do draw this lines in whole screen. How can i do that? It must draw everywhere in screen vertically. It now draws vertically but just one.
So far from your desired use case, I don't see any reason for you to use a custom view for this. You can set a custom background with repeat enabled:
res/drawable/MyBackground.xml
<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="#drawable/lines_image"
android:tileMode="repeat" />
Then for your view, set the background:
res/layout/whatever.xml
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/MyBackground" />
OR
myView.setBackgroundResource(R.drawable.MyBackground);
lines_image.png should be a 20px (or however much space between you want) wide image with your red line on the right.
It's an important concept for UI development. Don't do complicated things in code when a simple image solution will suffice.
If you absolutely **MUST** Do this in code, Then you just do the drawing in a loop for the width of the canvas.
private static final int LINE_SPACING = 20;
#Override
public void onDraw(Canvas canvas) {
for (int x = 0; x < canvas.getWidth(); x += LINE_SPACING) {
canvas.drawLine(x, 0, x, canvas.getHeight(), paint);
}
}

Android:Why after override onMeasure() in a custom view, the view's text can't show in RalativeLayout?

I made a custom component that extends View and overrides its onMeasure(), the content of this component is some text, then I add it to a RelativeLayout, but this text can't display, if I comment onMeasure() that been overridden the text shows. What's the reason?
Here is the code:
public class CustomView extends View {
private String text;
private int viewWidth;
private int viewHeight;
private Paint paint;
private FontMetrics fontMetrics;
public CustomView(Context context) {
this(context, null);
}
public CustomView(Context context, String text) {
this(context, text, 0);
this.text = text;
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
updateViewBounds();
}
public CustomView(Context context, String text, int defStyle) {
super(context);
}
private void updateViewBounds(){
viewWidth = (int) paint.measureText(this.text);
fontMetrics = paint.getFontMetrics();
viewHeight = (int)(fontMetrics.descent - fontMetrics.ascent);
}
private String getText() {
return this.text;
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(viewWidth, viewHeight);
//setMeasuredDimension(560, 100);even though give a ensured size, it can't //anyway.
}
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.setColor(Color.WHITE);
paint.setTextSize(30);
canvas.drawText(text, 0, 200, paint);
Log.e("content", ""+this.getText());
}
public boolean onTouchEvent (MotionEvent event){
Log.e("Touch", ""+this.getText());
return false;
}
}
Here is the Activity:
public class CustomViewActivity extends Activity {
/** Called when the activity is first created. */
private RelativeLayout contentLayout;
private CustomView view1;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
contentLayout = (RelativeLayout)findViewById(R.id.contentLayout);
view1 = new CustomView(this, "You drive me crazy!!!");
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
view1.setLayoutParams(layoutParams);
contentLayout.addView(view1);
}
}
this is the XML file:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/contentLayout"
android:layout_width="1024px"
android:layout_height="560px"
android:orientation="vertical" >
<Button
android:id="#+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_marginLeft="126dp"
android:text="Button" />
</RelativeLayout>
You can absolutely set the MeasureSpec to a different size, however, the arguments for onMeasure are misleading. A MeasureSpec is a specially translated int that has to be specifically created by using both a pixel measure and a flag. The correct way to set a specific size it indicated below...
final int desiredHSpec = MeasureSpec.makeMeasureSpec(pixelHeight, MeasureSpec.MODE_CONSTANT);
final int desiredWSpec = MeasureSpec.makeMeasureSpec(pixelWidth, MeasureSpec.MODE_CONSTANT);
setMeasuredDimension(desiredWSpec, desiredHSpec);
The MODE_CONSTANTS must have a value of one of the following:
* AT_MOST - meaning that it is dynamic, but will be clipped if the contents are too large
* EXACTLY - meaning it will be that size no matter how large or small the contents are
* UNSPECIFIED - meaning that it will make whatever decision it makes according to the parameters of the parents, children, device size, etc...
If you do not specify one of these constants, then the Android Layout rendering engine has no idea what to do, and simply hides the object. It must be understood, that as an open platform for so many devices, Google decided to make the layout engine "dynamic and intelligent" to support as many apps as possible on as many platforms as possible. This simply requires the developer to let the device know exactly what it needs.
Note: It sounds like you want EXACTLY, but think carefully about your choice and how many devices you will be supporting. :)

Scale image within custom ImageView

I'm extending ImageView in order to manually scale an image within the view. I want to scale an image to fill the width of the custom view, and then draw it to the canvas, however, I'm unable to get the view width using this.getWidth()
It just returns 0, as the view has not yet been drawn and so has dimensions 0 by 0.
Currently I have the following in my main.xml:
<com.android.myapp.BackgroundView
android:id="#+id/background_view"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:src="#drawable/background"
android:dither="true"
/>
The custom class is as follows:
public class BackgroundView extends ImageView {
private Paint paint;
private Bitmap background;
public BackgroundView(Context context) {
super(context);
paint = new Paint();
loadBitmap();
}
public BackgroundView(Context context, AttributeSet attrs) {
super(context, attrs);
paint = new Paint();
loadBitmap();
}
public void loadBitmap() {
BitmapDrawable src = (BitmapDrawable) this.getDrawable();
background = src.getBitmap();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(background, 0, 0, paint);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
My Main.java class is:
public class Main extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
I can't use
Bitmap.createScaledBitmap(background, view.getWidth(), view.getHeight(), false)
as the view hasn't yet been drawn, how would I go about scaling the image to fill the view/screen width at this point?
Thanks in advance.
I believe what you want to do could also be achieved by using ImageView directly in conjunction with the scaleType attribute. Either use fitXY or centerCrop, depending on your needs.
But to answer the question, you can only use getWidth() and getHeight() after layout() has been called. So you should be able to use the values inside your onDraw method.
Also you could use another drawBitmap method so you wouldn't have to create a new bitmap in memory.

Categories

Resources