Shape Drawable View in XML - android

I'm using the shapedrawable example word for word (nearly) and can't seem to call a shapedrawable class in xml. The only extra step stated by the documentation was to override the View(Context, AttributeSet), which I think I did. The docs I'm referring to are here: http://developer.android.com/guide/topics/graphics/2d-graphics.html Here is my code.
AndroidTest.java
package com.android.test;
import android.app.Activity;
import android.os.Bundle;
public class AndroidTest extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
ShapeSquare.java
package com.android.test;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.util.AttributeSet;
import android.view.View;
public class ShapeSquare extends View {
private ShapeDrawable mDrawable;
public ShapeSquare(Context context, AttributeSet attrs) {
super(context, attrs);
int x = 10;
int y = 10;
int width = 300;
int height = 50;
mDrawable = new ShapeDrawable(new OvalShape());
mDrawable.getPaint().setColor(0xff74AC23);
mDrawable.setBounds(x, y, x + width, y + height);
}
protected void onDraw(Canvas canvas) {
mDrawable.draw(canvas);
}
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<com.android.test.shapedrawable.ShapeSquare
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
The error is a force quit error and I can't figure out where the problem lies. The shape properties will be dictated by user input (eventually), so the shape needs to be created in a class as opposed to all xml.

Figured out the problem here. I had to remove "shapedrawable" from:
<com.android.test.shapedrawable.ShapeSquare
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
Apparently, that was just the location of the demo. I thought it was referencing the class somehow.

Related

Android: How to create custom view

I have to create a custom view to show a little graph on Android. There are a lot of tutorials but they didn't help me. They are full of resource handling, performance optimizations etc.
But I fail at the simplest thing: The view is not visible. Neither in Android Studio, nor in the running app.
Here my approach:
/home/thomas/dev/AndroidStudioProjects/Test/app/src/main/java/clear/test/MainActivity.java:
package clear.test;
import android.app.Activity;
import android.os.Bundle;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
/home/thomas/dev/AndroidStudioProjects/Test/app/src/main/java/clear/test/MyView.java:
package clear.test;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
public class MyView extends View {
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setColor(0xFF0000);
canvas.drawLine(0, 0, getMeasuredWidth(), getMeasuredHeight(), paint);
canvas.drawLine(getMeasuredWidth(), 0, 0, getMeasuredHeight(), paint);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(500, 500);
}
}
/home/thomas/dev/AndroidStudioProjects/Test/app/src/main/res/layout/activity_main.xml:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<clear.test.MyView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/view"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true" />
</RelativeLayout>
Your problem is that you use wrap_content for your view but do not implement the measure functions
1) Your view is "visible" but its height and width is 0 because of wrap_content in activity_main.xml. Try to set some absolute values or match_parent.
2) Do NOT create new instances of Paint in every call of onDraw. It`s useless.
3) If you want to define custom view both by java and xml (or I don't understand existence of file sample_my_view.xml), look for View's method inflate().
I found my problem:
Color is 32 bit. Red must be 0xFFFF0000, not 0xFF0000.

Strange behavior with Android view.invalidate()

I have 3 custom views placed vertically in a LinearLayout, they are used to display different dynamic info, so they're supposed be invalidated and redrawn at different time. But I found the view invalidation is out of usual expectation, that is: if you invalidate the top view,all 3 views are invalidated at the same time, if you invalidate the middle view, the middle and bottom views are invalidated, the top one is not, if you invalidate the bottom view, only the bottom view itself is invalidated, this is what I want, so what happened with the first 2 cases ? I searched and got similar questions like:
https://stackoverflow.com/questions/26192491/invalidate-one-view-force-other-views-invalidate-too-how-separating-that
Android Invalidate() only single view
but it seems no exact answer. I post my code here, any comment is appreciated.
TestView.java
package com.vrb.myview;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
public class TestView extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void onTest(View view){
MyView1 mv1 = (MyView1)findViewById(R.id.mv1);
MyView1 mv2 = (MyView1)findViewById(R.id.mv2);
MyView1 mv3 = (MyView1)findViewById(R.id.mv3);
mv1.invalidate(); // all 3 views are invalidated
// mv2.invalidate(); // mv2 and mv3 are invalidated
// mv3.invalidate(); // only mv3 is invalidated,this is what I want
}
}
MyView1.java
package com.vrb.myview;
import java.util.Random;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
public class MyView1 extends View {
Rect rc=null;
Paint p=null;
Random r;
public MyView1(Context ctx){
super(ctx);
rc = new Rect();
p = new Paint();
r = new Random();
}
public MyView1(Context ctx, AttributeSet set){
super(ctx, set);
rc = new Rect();
p = new Paint();
r = new Random();
}
public void onDraw(Canvas canvas){
if(canvas.getClipBounds(rc)){
Log.d("MyView1","id="+getId()+" Rect: "+rc.left+","+rc.top+","+rc.right+","+rc.bottom);
p.setColor(Color.argb(0xff, Math.abs(r.nextInt())%255, Math.abs(r.nextInt())%255, Math.abs(r.nextInt())%255));
canvas.drawRect(rc, p);
}else{
Log.d("MyView1","id="+getId()+" Rect=null");
}
}
}
main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/root"
android:orientation="vertical"
tools:context="com.vrb.myview.TestView" >
<com.vrb.myview.MyView1
android:layout_width="match_parent"
android:layout_height="100px"
android:id="#+id/mv1" />
<com.vrb.myview.MyView1
android:layout_width="match_parent"
android:layout_height="100px"
android:id="#+id/mv2" />
<com.vrb.myview.MyView1
android:layout_width="match_parent"
android:layout_height="100px"
android:id="#+id/mv3" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Invalidate"
android:onClick="onTest"
android:id="#+id/btn" />
</LinearLayout>
You shouldn't rely on the count or the time of the calls to onDraw() for the internal state of your View. Move the p.setColor() call to a separate public method, and call invalidate() at the end of it. For example:
public class MyView1 extends View {
...
public void changePaint() {
p.setColor(Color.argb(0xff, Math.abs(r.nextInt()) % 255, Math.abs(r.nextInt()) % 255, Math.abs(r.nextInt()) % 255));
invalidate();
}
}
Then in your onTest() method:
public void onTest(View view) {
MyView1 mv1 = (MyView1)findViewById(R.id.mv1);
...
mv1.changePaint();
...
}

Extended TextView not appearing

The following code is suppose to be doing this :
- Displaying a string using a standard TextView
- Displaying a string using a extended TextView. (This one overrides OnDraw and draws a line across the string, making it look like it was striked out)
The problem is that only the standard one is appearing.
Please check the following code :
ExpenseWatchActivity.java (This is the main activity)
package com.app.expensewatch;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
import java.util.Calendar;
public class ExpenseWatchActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
int day,mon,yr;
Calendar cal = Calendar.getInstance();
day = cal.get(Calendar.DATE);
mon = 1 + cal.get(Calendar.MONTH);
yr = cal.get(Calendar.YEAR);
String text = getResources().getString(R.string.hello, day , mon , yr);
TextView tx1 = (TextView)findViewById(R.id.text1);
tx1.setText(text);
List1 list = (List1)findViewById(R.id.list1);
list.setText(text);
}
}
List1.java (This is the extended TextView)
package com.app.expensewatch;
import android.util.AttributeSet;
import android.widget.TextView;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import com.app.expensewatch.R;
public class List1 extends TextView {
public List1(Context context) {
super(context);
}
public List1(Context context, AttributeSet attrs) {
super( context, attrs );
}
public List1(Context context, AttributeSet attrs, int defStyle) {
super( context, attrs, defStyle );
}
float ht = (float)getHeight();
float wd = (float)getWidth();
#Override
protected void onDraw(Canvas canvas)
{
Paint divider = new Paint();
divider.setColor(getResources().getColor(R.color.line1));
canvas.drawLine(0,ht/2,wd,ht/2,divider);
}
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/hello" />
<com.app.expensewatch.List1
android:id="#+id/list1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/hello" />
/>
</LinearLayout>
strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">ExpenseWatch</string>
<string name="hello">Today is : %1$d / %2$d / %3$d</string>
</resources>
colors.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="line1">#6456648f</color>
</resources>
When you set your width and height in the extended TextView, the view hasn't been measured yet. Its width and height are zero. Override onMeasure() in your extended TextView, and set your width and height there.
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
ht = getHeight();
wd = getWidth();
}
Always avoid setting a private variable that will hold a dimension in a view until after onMeasure() has been called.

InflateException (Error inflating class) when using custom widget in xml

I created a custom imageview. But I get an InflateException when I try to run this. Can someone help me solve this?
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#drawable/herinnering_background">
<be.test.ArrowImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/kompas_arrow_car"
/>
</FrameLayout>
package be.test;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.widget.ImageView;
public class ArrowImageView extends ImageView{
public ArrowImageView(Context context) {
super(context);
}
#Override
public void draw(Canvas canvas) {
super.draw(canvas);
Paint paint = new Paint(Paint.LINEAR_TEXT_FLAG);
paint.setColor(Color.GREEN);
paint.setTextSize(12.0F);
canvas.drawText("Hello World in custom view", 100, 100, paint);
}
}
I think the problem is that you need to implement a constructor with the AttributeSet because this is the one used by the LayoutInflator:
ImageView(Context context, AttributeSet attrs)

Android inflating xml layout generates RuntimeException

I'm new to Android and i'm trying to inflate a layout in xml but i get a RuntimeException. I have cut out almost everything except for my activity class and the class extending SurfaceView.
Can anyone tell me what i'm doing wrong?
main.xml:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.hj.Panel
android:id="#+id/SurfaceView01"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
Rita.java:
package com.hj;
import android.app.Activity;
import android.os.Bundle;
public class Rita extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
Panel.java:
package com.hj;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.SurfaceView;
class Panel extends SurfaceView {
private Paint mPaint;
public Panel(Context context) {
super(context);
}
#Override
public void onDraw(Canvas canvas) {
mPaint = new Paint();
canvas.drawRect(0, 0, 322, 644, mPaint);
}
}
In order to make your code run I had to do the following:
1) change "match_parent" to "fill_parent"
2) add constructor
public Panel(Context context, AttributeSet atts) {
super(context, atts);
}
You may want to try that
You should always post a stack trace when you report an exception. (Run adb logcat on the command line, or view the logcat window in eclipse).
Without that, my best guess is that it should be fill_parent, not match_parent.

Categories

Resources