ondraw view and xml in android - android

How can I draw an dynamic view on top of mainscreen in android.
For example I display the main screen using setContentView(R.layout.main);
This draws many widgets and includes an image defined in main.xml this way :
<ImageView
android:id="#+id/myImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/sinewave"/>
Now if I would like to draw rectangle on this image, how can I do it?
Thank you for your time.

To draw something on screen instead of using a pre-defined Widget:
You create a custom view class.
public class yourCustomView extends View {
}
You add that custom view to your xml layout.
<view class="your.package.path.yourCustomView"
android:id="#+id/myView"
android:layout_width="fill_parent"
android:layout_height="50dip"
/**you can add other xml attributes that are defined for View**/
/>
You override the onDraw() method to make it draw stuff you want on its canvas.
#Override
protected void onDraw(Canvas canvas) {
/**draw stuff here**/
}

Make sure you use this constructor if using the XML layout:
public yourCustomView(Context context, AttributeSet attrs) {
super(context, attrs);
}

Related

Why is Android Studio designer displaying my custom view nested inside itself, while it isn't

I've got a custom view for my app named AvatarView:
<?xml version="1.0" encoding="utf-8"?>
<com.ulouder.views.AdvancedRelativeLayout android:layout_width="wrap_content"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_gravity="center_horizontal"
android:layout_margin="0dp"
android:padding="0dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="CP"
android:id="#+id/initialsView"
android:layout_alignTop="#+id/avatarView"
android:layout_alignLeft="#+id/avatarView"
android:layout_alignBottom="#+id/avatarView"
android:layout_alignRight="#+id/avatarView"
android:background="#drawable/avatar_background"
android:textColor="#color/white"
android:gravity="center"
android:textStyle="bold"
android:textSize="8sp" />
<com.makeramen.roundedimageview.RoundedImageView
app:riv_corner_radius="20dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/avatarView"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginTop="4dp"
android:layout_marginLeft="4dp"
android:layout_marginBottom="4dp"
app:riv_border_color="#color/lightGray"
app:riv_border_width="0.2dp" />
</com.uLouder.views.AdvancedRelativeLayout>
AdvancedRelativeLayout is just a superclass of RelativeLayout with a small fix, nothing special there. Then, I've created a view that uses my custom view:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<com.ulouder.views.AvatarView
android:layout_width="50dp"
android:layout_height="50dp"/>
</LinearLayout>
Nothing fancy either. But in the designer view of the second layout XML, I'm getting this:
The editor displays my view hierarchy like it has a nested instance of itself, while clearly there isn't. If I delete either one, they both get deleted. If I declare attributes on one of them, other also gets it. They are clearly the same instance. The only exception is setting an ID. Then the problem disappears, and only single instance is displayed as expected.
I've rebuilt the project, restarted Android Studio, but it's still the same. What am I doing wrong?
UPDATE: Nope, now, after editing id, the problem still continues again.
UPDATE 2: It's not just a layout so I can't use <include> tag. It's a custom view which has custom logic inside.
UPDATE 3: Here is my custom view's (relevant) code:
public class AvatarView extends FrameLayout {
public AvatarView(Context context) {
super(context);
init();
}
TextView initialsView;
RoundedImageView imageView;
public AvatarView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
void init(){
inflate(getContext(), R.layout.view_avatar, this);
initialsView = (TextView) findViewById(R.id.innerInitialsView);
imageView = (RoundedImageView) findViewById(R.id.innerImageView);
}
#SuppressWarnings("SuspiciousNameCombination")
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, widthMeasureSpec); //always square
imageView.setCornerRadius(widthMeasureSpec / 2f);
initialsView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, widthMeasureSpec * 30f);
}
}
UPDATE 4: It appears that this happens wherever I put my custom AvatarView class, not just at one place.
I did not find any reason to inflate the same view inside your class constructor method after checking the custom views documentation. Try to remove the inflate inside your init method.
...
public AvatarView(Context context) {
super(context);
init();
}
...
public AvatarView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
void init(){
// inflate(getContext(), R.layout.view_avatar, this);
initialsView = (TextView) findViewById(R.id.innerInitialsView);
imageView = (RoundedImageView) findViewById(R.id.innerImageView);
}
...

Child view of a cutom RelativeLayout doesn't come to front

I have a custom Relative Layout(a class extended to RelativeLayout). I draw some bitmaps on a canvas using the method dispatchDraw(). And I want to show an Edit text box on top this canvas. So I create a new instance of EditText and bring it to front. EditText adds to the layout but doesn't come to front. When I remove canvas drawing code the edit text appears.
Help me if you know a way to bring the EditText to the front of the canvas.
public class EditCardLayout extends RelativeLayout {
public EditCardLayout (Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
editText = new EditText(context);
editText.setText("My Text");
addView( editText );
editText.bringToFront();
}
#Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
// some bitmaps are drawn here...
}
}
XML :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#eceadb"
android:gravity="center">
<editCard.EditCardLayout
android:id="#+id/cardEditView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true" />
</RelativeLayout>
What order are you adding the elements in? According to the docs, the z-order is affected by the order in which the elements are drawn, with the last thing drawn on top. Try adding the edittext last.

How to scroll bitmaps?

I have one image view (assigned one bitmap to it) and another bitmap (Transparent) for painting. How it is possible to scroll this bitmap and background bitmap at the same time to be painted at different places.
From what I understood you are trying to draw on top of a image. If thats the case, create a custom view and get the image using BitmapFactory. After you get a bitmap object, use its copy method and use that copy for the canvas of the view.
Now you can override the onDraw method of a custom view and draw anything on top of it.
This view can be added to the layout, and scrolling will happen to the view.
Edit: Sample Code
Ok this is some code that might help you. I dont have the time to go through all your code.
But I tried to understand your requirement.
I am showing the code for an activity, its xml and custom view
Activity.java
public class DrawDemo extends Activity {
private FrameLayout container;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.draw_demo_layout);
container = (FrameLayout)findViewById(R.id.sc);
container.addView(new DrawView(this));
}
public void drawHandler(View target){
container.addView(new DrawView(this));
}
public void clearHandler(View target){
if(container.getChildCount() != 1){
container.removeViewAt(container.getChildCount()-1);
}
}
}
draw_demo_layout.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">
<FrameLayout android:orientation="vertical"
android:layout_width="fill_parent" android:layout_height="0dip"
android:id="#+id/sc" android:scrollbars="horizontal"
android:layout_weight="1.0">
<ImageView android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:src="#drawable/chips"/>
</FrameLayout>
<Button android:layout_width="fill_parent"
android:layout_height="wrap_content" android:text="Draw"
android:onClick="drawHandler"/>
<Button android:layout_width="fill_parent"
android:layout_height="wrap_content" android:text="Clear"
android:onClick="clearHandler"/>
</LinearLayout>
DrawView.java
public class DrawView extends View {
public DrawView(Context context) {
super(context);
setLayoutParams(new LayoutParams(LinearLayout.LayoutParams.FILL_PARENT
,LinearLayout.LayoutParams.FILL_PARENT));
}
public DrawView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint p = new Paint();
p.setColor(Color.RED);
p.setStrokeWidth(5);
canvas.drawLine(50, 50, 100, 150, p);
canvas.drawLine(100, 150, 20, 50, p);
}
}
This activity has a framelayout which has a imageview as the base which holds the bitmap.
We add a custom draw view on top of it and do our drawings on it.When we want to clear the drawing we remove the drawview and add another one if we need to draw again.
This might not be the most efficient way. But should get you started.

dots in the viewFlipper view

I have a ViewFlipper view with two views inside it -
<ListView
android:dividerHeight="5dip"
android:id="#android:id/list"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:drawSelectorOnTop="false"
android:divider="#android:color/black">
</ListView>
<TextView
android:layout_height="fill_parent"
android:layout_gravity="bottom"
android:id="#+id/textView1"
android:layout_width="fill_parent">
</TextView>
</ViewFlipper>
How do i programmtically DRAW two little dots (or as many dots as there are children views inside the viewFlipper view)?
Should i override onDraw()?
My activity that inflates this ViewFlipper layout extends ListActivity...
Thanks.
Consider overriding dispatchDraw method (invoke super method and after that draw dots) because if you override onDraw the children's content will cover your dots.
Or create extension of horizontal linear layout containing view flipper at the top and some component at the bottom which manages ImageViews to show dots (or draws them manually).
public class CustomViewFlipper extends ViewFlipper {
public TableLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
drawDots(canvas);
}
}

Android: FrameLayout subclass does not draw

This is, what works:
a) FrameLayout with two ImageViews in main.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:id="#+id/frameLayout1"
android:layout_height="wrap_content">
<ImageView android:src="#drawable/radar_background"
android:id="#+id/background" android:layout_width="wrap_content"
android:layout_height="wrap_content"></ImageView>
<ImageView android:src="#drawable/radar_sector" android:id="#+id/sector"
android:layout_width="wrap_content" android:layout_height="wrap_content"></ImageView>
</FrameLayout>
b) RotateAnimation on the background, whereas the foreground sector remains unchanged
Because I need to do a bit more on the background image I put this into a FrameLayout subclass and changed main.xml accordingly:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:id="#+id/frameLayout1"
android:layout_height="wrap_content">
<com.decades.SensorTest.RadarView
android:id="#+id/background" android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<ImageView android:src="#drawable/radar_sector" android:id="#+id/sector"
android:layout_width="wrap_content" android:layout_height="wrap_content"></ImageView>
</FrameLayout>
This is the new RadarView.java:
public class RadarView extends FrameLayout {
private Bitmap mRadar;
public RadarView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public RadarView(Context context) {
super(context);
init();
}
private void init() {
mRadar = BitmapFactory.decodeResource(getResources(), R.drawable.radar_background);
}
#Override
public void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
canvas.drawBitmap(mRadar, 0, 0, null);
}
}
What happens:
a) The constructor is called during setContentView(R.layout.main);
b) The dispatchDraw override is called
c) The image does not appear on the screen...
Does anybody see, why?
I realize that this question is old, but it was never answered properly.
Implementing a View to put into the view group is a reasonable way to go, but sometimes you don't want to do that (say you have a view group class that arranges the contained views in some way).
In this case you need to draw from the layout (view group) view class.
I think that the given code should work, from reading through it, aside from the actual dispatchDraw function. You missed canvas.save() and canvas.restore().
Example that should be easy to get working quickly:
#Override
public void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
canvas.save();
canvas.drawCircle(cX, cY, bgRadius, bgPaint);
canvas.restore();
}
This has worked for me, at least, in my context. Hopefully it helps others who have the same problem. :)
Have you tried implementing onDraw() instead?
dispatchDraw() has to do with child Views.
I think you should extend the View class and override the onMeasure() and onDraw() methods.
More information here:
http://developer.android.com/guide/topics/ui/custom-components.html
Example:
http://www.barebonescoder.com/2010/06/android-development-simple-2d-graphics-part-1/
I'm guessing that you wanted to implement onDraw(), but that is probably not enough. To my understanding the layouts may not call onDraw if they have nothing to draw besides their children. You might need to "trick" the layout to draw itself (so you'll get the onDraw call). An easy yet not efficient way we did this (involved guesswork...) is to set the background color of the layout.
A better way is probably to read the layout code and do it properly :)

Categories

Resources