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);
}
}
Related
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
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'm trying to draw a line over an ImageView but whenever I try it using Canvas, I have to reload the Bitmap, which is not my intention.
Is there a way to simply draw a line on an uploaded ImageView using Canvas without having to refresh the Image? Or another way to draw lines over Android ImageView?
Or, if you want to be able to draw any lines (rects, ovals, etc), subclass ImageView into your own ImageView and do the drawing yourself.
public class MyImageView extends ImageView {
Paint linePaint = new Paint();
#Override
protected void onDraw(Canvas canvas) {
super.onDraw();
// And draw your line.
// (Be sure to have set the values/fields in linePaint earlier so that you draw the correct line/type/size/etc).
canvas.drawLine(0, getHeight()/2, getWidth(), getHeight()/2, linePaint);
}
}
And in your layout xml, don't specify <ImageView .../>, but specify <com.mycompany.project.widget.MyImageView ... /> instead.
The way that I draw lines in Android is by creating a View with height or width of 1dp. Then set the other value to whatever you want and set the color.
How do I grey out a view uniformly which contains many different items - ImageViews, TextViews, background image. Do I have to grey out each thing individually? Or is there a way to apply the same color filter to all?
Unless somebody else has a better answer, my current method is greying out each item separatedly.
PorterDuffColorFilter greyFilter = new PorterDuffColorFilter(Color.GRAY, PorterDuff.Mode.MULTIPLY);
myLayout.getBackground().setColorFilter(greyFilter);
myImageView.setColorFilter(greyFilter);
myTextView.setTextColor(0xff777777);
For more or nested children probably a loop with instanceof would be suitable but I don't need it.
Edit: This filter isn't actually grey, a better filter is here: Drawable => grayscale
Which can be used in the same way.
It's easy to do that by defining a custom view group as follows:
public class MyViewContainer extends XXXLayout {
//XXLayout could be LinearLayout, RelativeLayout or others
private Paint m_paint;
//define constructors here and call _Init() at the end of constructor function
private void
_Init()
{
ColorMatrix cm = new ColorMatrix();
cm.setSaturation(0);
m_paint = new Paint();
m_paint.setColorFilter(new ColorMatrixColorFilter(cm));
}
#Override protected void
dispatchDraw(Canvas canvas)
{
canvas.saveLayer(null, m_paint, Canvas.ALL_SAVE_FLAG);
super.dispatchDraw(canvas);
canvas.restore();
}
}
All children views of MyViewContainer will be shown in grey. :-)
Sam Lu's answer is a good start, but I had performance problems and decided to switch to hardware layers. With hardware layers, you can do it like this:
private final Paint grayscalePaint = new Paint();
ColorMatrix cm = new ColorMatrix();
cm.setSaturation(0);
grayscalePaint.setColorFilter(new ColorMatrixColorFilter(cm));
public void setGrayedOut(boolean grayedOut) {
if (grayedOut) {
setLayerType(View.LAYER_TYPE_HARDWARE, grayscalePaint);
} else {
setLayerType(View.LAYER_TYPE_NONE, null);
}
}
Be careful not to do the layers in dispatchDraw() itself as that will crash the app.
It depends entirely on the method you are using to "gray out" items. If you are doing so by calling setEnabled(false) on the parent ViewGroup, by default state flags (like disabled) do not trickle down to the child views. However, there are two simple ways you can customize this:
One option is to add the attribute android:duplicateParentState="true" to each child view in your XML. This will tell the children to get their state flags from the parent. This will mirror ALL flags however, including pressed, checked, etc...not just enabled.
Another option is to create a custom subclass of your ViewGroup and override setEnabled() to call all the child views as well, i.e.
#Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
for(int i=0; i < getChildCount(); i++) {
getChildAt(i).setEnabled(enabled);
}
}
What I like to do is create a view which overlaps the view you are trying to tint and set its background to a transparent color. Then you can turn the tint on and off by setting that views visibility
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ViewYouWantToTint
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<View
android:id="#+id/disabled_tint_overlay"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/darkTint"
android:visibility="invisible"/>
</FrameLayout>
Then in your controller:
m_DisabledBlackTintOverlay = (View) view.findViewById(R.id.login_disabled_black_tint_overlay);
m_DisabledBlackTintOverlay.setVisibility(View.VISIBLE);
If all you need to do is fade out or lighten the View colors the solution can be
View.setAlpha(#FloatRange(from=0.0, to=1.0) float alpha)
Which changes the transparency of the entire view
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);