my code is here
textPaint.setStyle(Paint.Style.FILL);
textPaint.setTextAlign(Paint.Align.CENTER);
canvas.drawText(substring, textX, y, this.textPaint);
I want to add here also cursor like edittext
You can draw blinking cursor this way:
private long lastCursorChangeState = -1;
private boolean cursorVisible = true;
private Rect textBounds = new Rect();
#Override
protected void onDraw(Canvas canvas) {
if(isWriting){
if(System.currentTimeMillis() - lastCursorChangeState > 500) {
cursorVisible = !cursorVisible;
lastCursorChangeState = System.currentTimeMillis();
}
if(cursorVisible){
paint.getTextBounds(textToDraw, 0, textToDraw.length(), textBounds);
canvas.drawLine(textX+textBounds.right, textY-textSize, textX+textBounds.right, textY, paint);
}
postInvalidateDelayed(500);
}
}
No, as far as i know it's not possible, because the text is part of a bitmap and not interpreted as text by the textmarker interface.
I would suggest another solution:
Use a encapsulated layout-structure like that (layout only simplyfied!)
<FrameLayout>
<Canvas />
<TextView />
<!-- More textviews -->
</FrameLayout>
You can position the textview inside the framelayout by calling the function setX or setY. The textview will then always be drawn on top of the canvas, as long as the textview is defined after the canvas. Furthermore you can make it visible/invisible by code by calling the function setVisibility
In addition to that, you can add more Textviews to the framelayout dynamically using code instead of defining the textview statically in the layout xml
Related
I'm drawing a tooltip after clicking inside a custom bar chart (created with MPAndroidChart). The view hierarchy is as follows
<LinearLayout>
<TextView text=Move & Max Pain/>
<RelativeLayout with 2 textviews>
<chart
clipToChildren=false
clipToPadding=false
/>
</LinearLayout>
While the View is inside the Chart or its inmediate sibling, everthing looks good. But the moment it collides with its sibling, the tooltip is truncated
Using HierarchyViewer I can see that the content is present, but it's not drawn.
In order to get the clipping, I'm using this code inside draw
#Override
public void draw(Canvas canvas, float posx, float posy) {
// take offsets into consideration
posx += getXOffset();
posy += getYOffset();
canvas.save();
// translate to the correct position and draw
canvas.translate(posx, posy);
Rect clipBounds = canvas.getClipBounds();
clipBounds.inset(0, -getHeight());
canvas.clipRect(clipBounds, Region.Op.INTERSECT);
draw(canvas);
canvas.translate(-posx, -posy);
canvas.restore();
}
If I change Op to Region.Op.Replace, the tooltip is draw correctly but it replaces the Toolbar content, instead of scrolling under it.
You'll need the bounds of the area in which you want to be able to draw the tooltip, and I'm assuming that would be a scrollview. Then you can intersect the tooltip bounds with the scroll to work out what the clipping should be; and if it should be drawn at all.
To explain it in code it would be something like this (untested):
Rect scrollViewRect; // the bounds of your scrollview
Rect tooltipRect; // the bounds of your tooltip
bool intersects = tooltipRect.intersect(scrollViewRect)
if(intersects)
{
canvas.clipRect(tooltipRect, Region.Op.REPLACE);
draw(canvas);
}
I would like to add TextView and EditView into my custom LinearLayout programmatically.
But I don't know how.
Something like this (that doesn't work):
<com.custom.FavoritesViewer
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:visibility="gone"
android:id="#+id/favoritesViewer">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello"/>
</com.custom.FavoritesViewer>
and my custom layout
public class FavoritesViewer extends LinearLayout {
private Bitmap fullImage;
private int canvasWidth;
private int canvasHeight;
private final Paint paint = new Paint();
public FavoritesViewer(Context context, AttributeSet attrs) {
super(context, attrs);
setWillNotDraw(false);
initializeCanvasSize(context);
}
private void initializeCanvasSize(Context context) {
final Pair<Integer, Integer> screenSize = Utils.getScreenSize(context);
canvasWidth = screenSize.first;
canvasHeight = screenSize.second;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(canvasWidth, canvasHeight / 3);
}
#Override
protected void onDraw(Canvas cvs) {
if (fullImage == null) {
fullImage = Bitmap.createBitmap(canvasWidth, canvasHeight / 3, Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(fullImage);
paint.reset();
paint.setColor(Color.parseColor("#AA000000"));
canvas.drawRect(0, 0, canvasWidth, canvasHeight / 3, paint);
}
cvs.drawBitmap(fullImage, 0, 0, null);
}
}
So I have a canvas (like background) and I would like to add some standart Views on top. I cannot add it on onDraw.
Is it any way to add View into custom Layout?
EDITTED
I need to implement some special UI with buttons. I want to wrap this in one component. I draw that UI on canvas and somehow should add buttons (It's enough for me to add simple ImageButton, not to draw an image and emulate button's behaviour). That's why I selected Layout as container and need to add Views programmatically.
As long as you call through to super (probably super.onDraw()), I imagine the parent class will draw the views you add as expected. It looks like you're just overriding onDraw, which would prevent the parent LinearLayout class from rendering it's content (like the TextView).
Try commenting out your onDraw method first, and see if the LinearLayout behaves as expected.
Also, what's the goal of the Custom Layout? There may be a better way to achieve your goal.
For a custom AdapterView implementation I'd like to add a color overlay to selected items. How do I add a color overlay to a child of my AdapterView?
If you are using your own layout simply change the container to RelativeLayout (or a Layout class that inherits from RelativeLayout), and put the color overlay after the main layout. All you need is to add a View and set it's background and alpha. alpha set to the value 1 will activate this overlay, whereas setting alpha to 0 will go back to normal.
Example:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- add your views here -->
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#8000FF00" />
</RelativeLayout>
This will overlay a green layer with 50% alpha over the other views which are before it in the layout.
OK, I did some more research. That's what I finally came up with:
// prepare a gray filter setting saturation to 0, or ...
ColorMatrix cm = new ColorMatrix();
cm.setSaturation(0);
Paint paint = new Paint();
ColorFilter filter = new ColorMatrixColorFilter(cm);
// ... prepare a color filter
ColorFilter filter = new PorterDuffColorFilter(Color.rgb(34, 136, 201), PorterDuff.Mode.OVERLAY);
// create paint
paint.setColorFilter(filter);
// override dispatchDraw of the view
#Override
protected void dispatchDraw(Canvas canvas) {
if (isPressed()) {
canvas.saveLayer(null, paint, Canvas.ALL_SAVE_FLAG);
super.dispatchDraw(canvas);
canvas.restore();
} else {
super.dispatchDraw(canvas);
}
}
I want to create a layer with transparent layer over an activity and I need to make visible only a particular view, say for an example "Login Button". It something mean that making hole on layer exactly the size of the button. Please anyone help me out of this.
Thanks In advance.
Programatically, you can use Canvas to create a layer. Fill the whole thing with your color and cut out a hole.
public class DrawView extends View {
Paint paint = new Paint();
Paint transparentPaint = new Paint;
public DrawView(Context context) {
super(context);
}
#Override
public void onDraw(Canvas canvas) {
//first fill everything with your covering color
paint.setColor(yourTransparentColor);
canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), paint);
//now clear out the area you want to see through
transparentPaint.setAlpha(0xFF);
transparentPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
Rect rect=new Rect(left, top, right, bottom);//make this your rect!
canvas.drawRect(rect,transparentPaint);
}
}
If I understand your question correctly
Your parent Layout of the Activity will be a RelativeLayout. In your parent layout at the bottom add another child RelativeLayout that implments the match_parent parameters for both width and height. You can then set a color like this #99000000 to it's background. This will give you a black transparent layer over your parent.
Something like this
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/parentLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF">
<!-- here you add your activities views ect... -->
<RelativeLayout
android:id="#+id/childLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#99000000">
<!-- This will be your overlay so here you can add your login button ect -->
</RelativeLayout>
</RelativeLayout>
I didn't test this but it should solve your issue
On following "HalR" Steps , I was able to achieve the transparent background Thanks to him and found some of you are getting pitch black on the cut made over transparent layer is due to Graphic rendering . that can be enabled using below code inside onDraw method
` #Override
public void onDraw(Canvas canvas) {
if (android.os.Build.VERSION.SDK_INT >= 11) {
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
.....
..... // your draw rect creation and other stuff `
which will let you have the transparent area by eliminating the Pitch black color
If i understood your question then this is what you wanted:
You tried to overlay a transparent view on your activity and cut out holes to see few stuffs.
here i found an useful example which shows how can you cut out bitmaps and combine them. i would suggest for your problem just take the part of cutting the bitmap and remember to set the imageview backgroung with opacity as shown here
android:background="#00ffffff"
here is the layout i created
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#android:color/transparent"
android:src="#drawable/ic_launcher"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"/>"
<ImageView
android:id="#+id/img"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#00ffffff"
android:scaleType="centerCrop" >
</ImageView>
</RelativeLayout>
and this is my maniactivity
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageView iv = (ImageView) findViewById(R.id.img);
Bitmap foreground = BitmapFactory.decodeResource(getResources(), R.drawable.android_cat_wanted);
foreground = punchAHoleInABitmap(foreground);
iv.setImageBitmap(foreground);
}
private Bitmap punchAHoleInABitmap(Bitmap foreground) {
Bitmap bitmap = Bitmap.createBitmap(foreground.getWidth(), foreground.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
canvas.drawBitmap(foreground, 0, 0, paint);
paint.setAntiAlias(true);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
float radius = (float)(getScreenSize().x *.35);
float x = (float) ((getScreenSize().x*.5));
float y = (float) ((getScreenSize().y*.5));
canvas.drawCircle(x, y, radius, paint);
return bitmap;
}
#SuppressLint("NewApi")
private Point getScreenSize() {
WindowManager window = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
Display display = window.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
return size;
}
}
hope you find it useful
I am using the onDispatchDraw(Canvas canvas) method to draw lines in my view. When I call canvas.drawLine() it always draws the line on top of all my views. Is there any way to draw the line under a button but on top of another view in my layout using canvas.drawLine()?
I have tried the following but it still draws the line over the button.
Button b;
RelativeLayout r;
#Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
Paint p = new Paint();
p.setColor(Color.Black);
canvas.drawLine(0,0,100,100,p);
r.removeView(b);
r.addView(b);
}
You're trying to reinvent the wheel. Z-ordering is already implemented in the window management subsystem and you can use it.
Create a custom view you want to draw on.
Make it non-clickable using android:clickable="false" or setClickable(false).
Make its background transparent and implement dispatchDraw().
Put all the views you don't want to draw on above this view in the view hierarchy.
Call super.dispatchDraw() after drawing the line. The dispatchDraw is called by viewgroup for drawing its children, so in your case, calling super.dispatchDraw() will draw the button first then you are drawing the line over it. Do dispatchDraw this way :
Updated code
class myListViewWithLine extends ListView {
....
#Override
protected void dispatchDraw(Canvas canvas) {
Paint p = new Paint();
p.setColor(Color.Black);
canvas.drawLine(0,0,100,100,p);
super.dispatchDraw(canvas);
}
....
}
Another method will be to just add a view with 1 dip as height and background color whatever you like under the button. It should look like like a line.
View v = new View(this);
ViewGroup.LayoutParams lp = new LayoutParams(LayoutParams.FILL_PARENT,1);
v.setLayoutParams(lp);
v.setBackgroundColor(Color.WHITE);
addView(v,INDEX NUMBER AFTER THE BUTTON);