I'm trying to create a View with rounded corners (and a background color of choice) that I can reuse with different background colors; hard to explain, so here's my code:
/app/src/com/packagename/whatever/CustomDrawableView.java
package com.packagename.whatever;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.drawable.PaintDrawable;
import android.util.AttributeSet;
import android.view.View;
public class CustomDrawableView extends View {
private PaintDrawable mDrawable;
int radius;
private void init(AttributeSet attrs) {
TypedArray a = getContext().obtainStyledAttributes(attrs,R.styleable.RoundedRect);
radius = a.getInteger(R.styleable.RoundedRect_radius, 0);
}
public CustomDrawableView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
mDrawable = new PaintDrawable();
}
protected void onDraw(Canvas canvas) {
mDrawable.setCornerRadius(radius);
mDrawable.draw(canvas);
}
}
Here's the XML to display the custom component:
/app/res/layout/test.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:ny="http://schemas.android.com/apk/res/com.packagename.whatever"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#ffffff"
android:padding="10dp">
<com.packagename.whatever.CustomDrawableView
android:id="#+id/custom"
android:layout_width="200dp"
android:layout_height="200dp"
android:background="#b80010"
ny:radius="50"
/>
</LinearLayout>
I'm wanting the red box to have 50px rounded corners, but as you'll see, it does not:
The idea is that I could easily change the background color in the XML and automatically have a nice View with rounded corners, without having to create multiple drawables.
Thanks for the help!
You need to set your corner radius and color into the background drawable.
Here is one way that would work. Grab the color you set in android:background, then use it to create a new drawable that you set into the background in the constructor. This will work as long as you only set android:background to a color value.
public CustomDrawableView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
// pull out the background color
int color = attrs.getAttributeIntValue("http://schemas.android.com/apk/res/android", "background", 0xffffffff);
// create a new background drawable, set the color and radius and set it in place
mDrawable = new PaintDrawable();
mDrawable.getPaint().setColor(color);
mDrawable.setCornerRadius(radius);
setBackgroundDrawable(mDrawable);
}
If you override onDraw, make sure you call super.onDraw(canvas) first to get the background drawn.
given a simple shapedrawable like this:
public ShapeDrawable Sd(int s){
float[] outerR = new float[] { 12, 12, 12, 12, 12, 12, 12, 12 };
ShapeDrawable mDrawable = new ShapeDrawable(new RoundRectShape(outerR, null,null));
mDrawable.getPaint().setColor(s);
return mDrawable;
}
you can do the following:
LinearLayout l=(LinearLayout) findViewById(R.id.testLayout);
l.setBackgroundDrawable(Sd(0xff74AC23));
where the 12's represent the radius.
you could apply this to any view for a background drawable.
Take a look at this question: How do I set the rounded corner radius of a color drawable using xml?
And perhaps also these two:
How to add rounded corner to a drawable I'm using as a background in Android?
How should I give images rounded corners in Android?
Related
I am using that "hack".
I have read here in stackoverflow.
#Override
public void draw(Canvas canvas) {
for (int i = 0; i < 20; i++) {
super.draw(canvas);
}
}
But my border still smoothie,I wanna put a large and solid border on all my TextView (I already have my component extend a textview).
I have a selector in text color when I click in this text the text color need to change.(It was already working,but I tried to apply another alternative using canvas,in this alternative,I lost this comportment).
This page solve your problem, you can custom the style:
How do I put a border around an Android textview?
You can set a shape drawable (a rectangle) as background for the view.
<TextView android:text="Some text" android:background="#drawable/back"/>
And rectangle drawable back.xml (put into res/drawable folder):
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
<solid android:color="#ffffff" />
<stroke android:width="1dip" android:color="#4fa5d5"/>
</shape>
You can use #00000000 for the solid color to have a transparent background. You can also use padding to separate the text from the border. for more information see: http://developer.android.com/guide/topics/resources/drawable-resource.html
Your current solution (the hack) is working fine, you just have to tweak 2 parameters accordingly to get a better "solid" shadow effect.
Parameters
The 1st parameter is the shadow radius of the TextView. This parameter decides how "wide" the blur (shadow) effect will spread behind your letter.
The 2nd parameter is the repeat counter of the for loop that wraps around your TextView's onDraw(...) method. Higher repeat count will get you a more "solid" shadow by trading off the performance.
"Solid" shadow
The rule here is, increment on shadow radius (↑) must always accompany with increment on repeat counter (↑) to achieve the "solid" shadow effect.
Similarly, if you want to gain performance by reducing repeat counter (↓), you have to decrease shadow radius (↓) as well.
Solid shadow TextView
package com.example.solidshadowtext;
import android.content.Context;
import android.graphics.Canvas;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.widget.TextView;
public class SolidShadowTextView extends TextView {
/**
* Shadow radius, higher value increase the blur effect
*/
private static final float SHADOW_RADIUS = 10f;
/**
* Number of times a onDraw(...) call should repeat itself.
* Higher value ends up in more solid shadow (but degrade in performance)
* This value must be >= 1
*/
private static final int REPEAT_COUNTER = 10000;
// Shadow color
private static final int SHADOW_COLOR = 0xff000000;
public SolidShadowTextView(Context context) {
super(context);
init();
}
public SolidShadowTextView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
#Override
protected void onDraw(Canvas canvas) {
for (int i = 0; i < REPEAT_COUNTER; i++) {
super.onDraw(canvas);
}
}
#Override
public void setShadowLayer(float radius, float dx, float dy, int color) {
// Disable public API to set shadow
}
private void init() {
super.setShadowLayer(SHADOW_RADIUS, 0, 0, SHADOW_COLOR);
}
}
Sample
1) Is it possible to create drawable, example
static Bitmap.Config conf = Bitmap.Config.ARGB_8888;
static Bitmap bmp = Bitmap.createBitmap(100, 100, conf);
// something draw
// eventually convert to DrawableBitmap
and then convert it / asiggn as / put in resource, to use in function with resource id param, like:
public void setWidgetLayoutResource (int widgetLayoutResId)
or
2) is it possible to dynamically draw to change image in R.drawable.something.bmp?
All this for change color of widget in setWidgetLayoutResource() to any color, not fixed as color of concrete resource
My own answer
This question is relative to my other: Android PreferenceScreen
and I was do it in this way:
ColorLinesView.java
public class ColorLinesView extends View
{
private static GradientDrawable gdDefault = new GradientDrawable();
public static int fillColor;
public ColorLinesView(Context context, AttributeSet attrs)
{ super(context, attrs);
}
#Override protected void onDraw(Canvas cv)
{
gdDefault.setColor(fillColor);
gdDefault.setCornerRadius(4);
gdDefault.setStroke(2, 0xffbbbbbb);
this.setBackgroundDrawable(gdDefault);
}
}
color_lines_accesory.xml
<?xml version="1.0" encoding="utf-8"?>
<android.swp.ColorLinesView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/colorBoxLines"
android:layout_width="52dp"
android:layout_height="26dp"
android:gravity="right"
android:layout_marginRight="6dp" />
and finally while programmatically create PreferenceScreen, after add category preference "somePref":
ColorLinesView.fillColor = 0xff00ff00; // examply green
somePref.setWidgetLayoutResource(R.layout.color_lines_accesory);
and the same two lines (with new color) in OnPreferenceClickListener() for "somePref" category, after using color picker to change color.
result:
I am using keyboard view where i have custom xml shape thath i can set specific buttons a color here is my shape xml:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#80B3B3B3"/>
<corners android:bottomRightRadius="2dp" android:bottomLeftRadius="2dp"
android:topLeftRadius="2dp" android:topRightRadius="2dp"/>
</shape>
Then I overwrite my onDraw method for Keyboard View:
#Override
public void onDraw(Canvas canvas)
{
super.onDraw(canvas);
List<Key> keys = getKeyboard().getKeys();
for (Key key : keys) {
Drawable dr = (Drawable)this.getResources().getDrawable(R.drawable.keyshape);
dr.setBounds(key.x, key.y, key.x + key.width, key.y + key.height);
dr.draw(canvas);
}
}
Now I want to allow that user set this color of Shape any idea how can I set this before drawing?
First of all, you should do a custom view that you want to set and extend it (TextView or Button w/e I will write sample as extending View) since you are not able to edit shape xml programmatically, you will create it as a whole.
Override needed behaviours and constructors for your View. Now you will create a method setGradientColors that take two colours as int values (bottom and top gradient colors). You can modify it for setting radius for rounded corners as well.
public class GradientView extends View{
public GradientView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public GradientView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// TODO Auto-generated constructor stub
}
public GradientView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
public void setGradientColors(int bottomColor, int topColor) {
GradientDrawable gradient = new GradientDrawable(Orientation.BOTTOM_TOP, new int[] {bottomColor, topColor});
gradient.setShape(GradientDrawable.RECTANGLE);
gradient.setCornerRadius(10.f);
this.setBackgroundDrawable(gradient);
}
}
You are going to use this new view and set shape programmatically as:
GradientView view = (GradientView) findViewById(R.id.customView);
// bottom color - top color order
view.setGradientColors(Color.parseColor("#ff0000"), Color.parseColor("#0000ff"));
If you need further assistance and full explanation about basics, I have achieved this in my project by following this Link
Hope it is going to help you as well.
You can't change shape colour pro grammatically either you have to create new shape with different colour or you can use :
imageView.getBackground().setColorFilter(Color.parseColor("#BBBDBF"), Mode.MULTIPLY);
imageview.invalidate();
it will multiply the given colour code with your image background and will show effect of colour changed.
If you want change only the colors on the shape from the xml drawable, I changed your onDraw a little to do it.
It will be a GradientDrawable if you define it in xml with <shape> tag.
Drawable dr = this.getResources().getDrawable(R.drawable.keyshape);
if (dr instanceof GradientDrawable) {
GradientDrawable gradientDr = (GradientDrawable) dr;
gradientDr.setBounds(key.x, key.y, key.x + key.width, key.y + key.height);
gradientDr.setColor(Color.GREEN);
gradientDr.draw(canvas);
}
I am using a custom seekbar to show a graph. I had done till this. I am showing this graph by applying a background drawable to the seekbar. Now my problem is, I need to set the blue one as progress drawable and need to set the background of seekbar as the red graph. So that when progress happens thumb moves over red the area where thumb passed should be changed to blue color like a masking effect. Can any one tell the best possible way to do this. My pictures are shown below
After reading all the questions and answers I hope this should be your scenario to get your thing done...
1.Create two graphs
As per your logic.
2.Generate two drwables from the particular bitmaps....
Drawable G_bg = new BitmapDrawable(Red graph bitmap);
Drawable G_pg = new BitmapDrawable(Blue graph bitmap);
3.And then customize your seek bar using layer list created through the java code.
ClipDrawable c=new ClipDrawable(G_pg, Gravity.LEFT,ClipDrawable.HORIZONTAL);
LayerDrawable ld =new LayerDrawable (new Drawable[]{G_bg,c});
4.Apply this layer list to your seekbar.
Graphbar.setProgressDrawable(ld);
This should work like you wanted....Thanksss
Is this not what you wanted?
my_seek_bar_progress.xml:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="#android:id/background"
android:drawable="#drawable/red_graph"/>
<item android:id="#android:id/progress">
<clip android:drawable="#drawable/blue_graph" />
</item>
</layer-list>
in Fragment or Activity layout:
<com.example.seekbaroverlay.MySeekBar
android:id="#+id/mySeekBar1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="100" />
MySeekBar.java:
public class MySeekBar extends SeekBar {
public MySeekBar(Context context) {
this(context, null);
}
public MySeekBar(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MySeekBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setProgressDrawable(context.getResources().getDrawable(R.drawable.my_seek_bar_progress));
setThumb(context.getResources().getDrawable(R.drawable.my_thumb));
}
}
You should use a custom progressDrawable for your SeekBar. See this blog post for a great tutorial.
You can create a custom view.Override it's onTouch() method to change position of thumb.Also override it's onDraw() method and first draw red graph as background of your view and then the blue one from position that corresponds to the position of thumb.
Here is my unanswered question:
Add new item count to icon on button - Android
Basically I want to display "new" counts on top. I see it as overlaying some view over existing button. How this can be done?
Easiest thing to do is:
Use a RelativeLayout with layout_height and layout_width set to WRAP_CONTENT.
Put one Button into the RelativeLayout with layout_height and layout_width set to WRAP_CONTENT.
Add an ImageView into the RelativeLayout aligned to PARENT_TOP and PARENT_RIGHT and set the visibility to GONE.
Then you can simply set the ImageView's drawable to the appropriate count image and set the visibility to VISIBLE.
Ok here is what i'd do:
Create a custom control that extends button. I'm not going to do the pretty graphics for you but this will give you the basic idea:
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.widget.Button;
public class CounterButton extends Button{
protected int count=0;
protected final Paint myTextPaint = new Paint();
protected final Paint myCirclePaint = new Paint();
public CounterButton(Context context, AttributeSet attrs) {
super(context, attrs);
this.setBackgroundDrawable(getResources().getDrawable(android.R.drawable.ic_dialog_email));
this.myCirclePaint.setARGB(150, 255, 0, 0);
this.myTextPaint.setARGB(150, 255, 255, 255);
}
#Override
protected void onDraw(Canvas canvas) {
if(count!=0){
canvas.drawCircle((float) (this.getWidth()*.75), (float) (this.getHeight()*.4), this.getHeight()/5, myCirclePaint);
canvas.drawText(Integer.toString(count), (float) (this.getWidth()*.75), (float) (this.getHeight()*.4), this.myTextPaint);
}
}
}
Clean up the sizing of your text you draw, the circle positioning (and add a border etc) and you have a custom control. You could further extend it so you could set the background in xml or dynamically and you have a reusable control with a number counter in a circle.
then in your code you could do:
CounterButton cb=(CounterButton) findViewById(R.id.whateverYouGaveItInXML);
cb.count=SomeNewNumber;
cb.invalidate;
the invalidate will redraw the image with the new value in the circle.
I used a button in the event you want to have it clickable easily and all that - but you could just as easily extend view if you are just doing a view.