Change gradient center dynamically - android

I have the following gradient
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:angle="90"
android:centerColor="#42f448"
android:centerX="0.5"
android:centerY="0.5"
android:endColor="#000000"
android:startColor="#000000"
android:type="linear" />
What I need to do is change the center of the gradient based on position change on a ListView. Is it possible to create this gradient programmatically?
I've tried this approach, but if I change the center values, nothing happens, it remains fixed:
int colors[] = {0xff000000, 0xff42f448, 0xff000000};
GradientDrawable shape = new GradientDrawable();
shape.setOrientation(GradientDrawable.Orientation.TOP_BOTTOM);
shape.setColors(colors);
shape.setGradientCenter(0.3f, 0.3f);
view.setBackgroundDrawable(shape);
What am I missing? Thank you.

You can achieve your goal by using Shader
ShapeDrawable.ShaderFactory sf = new ShapeDrawable.ShaderFactory() {
#Override
public Shader resize(int width, int height) {
return new LinearGradient(width/2, 0, width/2, height,
new int[]{0xff000000, 0xff42f448, 0xff000000},
new float[]{0, 0.3f, 1}, // start, center and end position
Shader.TileMode.CLAMP);
}
};
PaintDrawable pd = new PaintDrawable();
pd.setShape(new RectShape());
pd.setShaderFactory(sf);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
layout.setBackground(pd);
} else
layout.setBackgroundDrawable(pd);

Related

convert drawable xml containing a gradient to bitmap

I want to apply a gradient to a bitmap. So far I'm using this technique.
here is my code in the onCreate method of MainActivity.class.
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
double angle = Math.toRadians(135);
double length = 100;
int x = (int) (Math.cos(angle) * length);
int y = (int) (Math.sin(angle) * length);
int[] colors = new int[3];
colors[0] = Color.parseColor("#FF4081");
colors[1] = Color.parseColor("#3F51B5");
Bitmap bitmap = Bitmap.createBitmap(1080, 1080, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
LinearGradient linearGradient =
new LinearGradient(0, 0, x, y, colors[1], colors[0], Shader.TileMode.CLAMP);
Paint paint = new Paint();
paint.setDither(true);
paint.setShader(linearGradient);
canvas.drawRect(new RectF(0, 0, 1080, 1080), paint);
ImageView imageView = findViewById(R.id.iv);
imageView.setImageBitmap(bitmap);
}
}
which results in this
but I want to get an effect like this
image 2 results were achieved by simply creating a drawable XML file with the following code
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:angle="45"
android:endColor="#color/colorPrimary"
android:startColor="#color/colorAccent" />
</shape>
and setting it as a background for an ImageView, but I want this effect on the bitmap because I want to save that bitmap locally as an Image. I have tried creating a GradientDrawable instance in the MainActivity and calling onDraw(canvas) on the GradientDrawable as mentioned in the post
As I see, you calculated the angle incorrect.
Instead of this
LinearGradient linearGradient =
new LinearGradient(0, 0, x, y, colors[1], colors[0], Shader.TileMode.CLAMP);
Use this
LinearGradient linearGradient =
new LinearGradient(1080, 0, 0, 1080, colors[1], colors[0], Shader.TileMode.CLAMP);
x0 is gradient start X, y0 is gradient start Y, x1 is gradient end X and y1 is gradient end Y.
Hope I helped you.

Rounded scaled ImageView from right side only

How can I round an image that is scaled (CenterCrop) from right-top and right-bottom (all right side) only.
This is what I am trying to do.
I found that class that can do similar (TopRoundedImage, thanks to the author) but for top-left and top-right. I am trying to change it but I guess I am still doing it wrong.
Also, I am using Glide to request the image from Internet then I want to round right side only.
I have tried to use a background drawable, but it doesn't work (I read it is because of the scale).
public class RightRoundedImageView extends AppCompatImageView
{
private final RectF roundRect = new RectF();
private float rect_radius = 7;
private final Paint maskPaint = new Paint();
private final Paint zonePaint = new Paint();
public RightRoundedImageView(Context context, AttributeSet attrs)
{
super(context, attrs);
init();
}
public RightRoundedImageView(Context context)
{
super(context);
init();
}
private void init()
{
maskPaint.setAntiAlias(true);
maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
zonePaint.setAntiAlias(true);
zonePaint.setColor(Color.WHITE);
float density = getResources().getDisplayMetrics().density;
rect_radius = rect_radius * density;
}
public void setRectAdius(float radius)
{
rect_radius = radius;
invalidate();
}
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom)
{
super.onLayout(changed, left, top, right, bottom);
int w = getWidth();
int h = getHeight();
// roundRect.set(0, 0, w, h + rect_radius);//round top
roundRect.set(0, 0, w + rect_radius, h); //round left
// roundRect.set(0, 0, w - rect_radius, h); //round all
}
#Override
public void draw(Canvas canvas)
{
canvas.saveLayer(roundRect, zonePaint, Canvas.ALL_SAVE_FLAG);
canvas.drawRoundRect(roundRect, rect_radius, rect_radius, zonePaint);
canvas.saveLayer(roundRect, maskPaint, Canvas.ALL_SAVE_FLAG);
super.draw(canvas);
canvas.restore();
}
}
If anyone know or can help, it would be appreciated. Thanks.
you can use drawable shape for this :
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#FFFFFF"/>
<stroke android:width="3dip" android:color="#B1BCBE" />
<corners android:bottomLeftRadius="0dp" android:bottomRightRadius="10dp"
android:topLeftRadius="0dp" android:topRightRadius="10dp"/>
<padding android:left="0dip" android:top="0dip" android:right="0dip" android:bottom="0dip" />
</shape>
imageView.setBackground(this.getResources().getDrawable(R.drawable.my_shape));
also check this link question how-to-make-an-imageview-with-rounded-corners

Changing shape in appWidget

I'm trying to change the color in the shape of an appWidget. I have a rectangle with corners, my goal is to change the background(solid) color and the border colors.
My widget layout is a RelativeLayout with an ImageView for the background, the src attribute of this ImageView is this shape :
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<corners
android:radius="5dp"
android:topRightRadius="5dp"
android:bottomRightRadius="5dp"
android:bottomLeftRadius="5dp" />
<stroke
android:width="1dp"
android:color="#android:color/white" />
<solid android:color="#color/transparent"/>
</shape>
Here is what I'm trying to do when I try to change the background color :
RoundRectShape sd = new RoundRectShape(new float[]{30,30,30,30,30,30,30,30}, null, null);
bmp_bg = Bitmap.createBitmap(200, 20, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bmp_bg);
Paint p = new Paint();
p.setColor(0xFF0000FF);
sd.draw(c, p);
remoteViews.setImageViewBitmap(R.id.imageClock, bmp_bg);
But the background doesn't change. Is this a good way to do that ? Or am I completly wrong ?
thx
EDIT :
I tried this too without any effect :
CustomShapeClockWidget cscw = new CustomShapeClockWidget(0xFF0000FF, 0xFFFF0000);
bmp_bg = Bitmap.createBitmap(200, 20, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bmp_bg);
cscw.draw(c);
remoteViews.setImageViewBitmap(R.id.imageClock, bmp_bg);
with the class CustomShapeClockWidget being :
public class CustomShapeClockWidget extends ShapeDrawable {
private int bgColor, strokeColor;
private Paint fillPaint, strokePaint;
public CustomShapeClockWidget(int bgColor, int strokeColor){
this.bgColor = bgColor;
this.strokeColor = strokeColor;
}
#Override
protected void onDraw(Shape shape, Canvas canvas, Paint paint){
fillPaint = this.getPaint();
strokePaint = new Paint(fillPaint);
fillPaint.setColor(bgColor);
strokePaint.setStyle(Paint.Style.STROKE);
strokePaint.setStrokeWidth(1.0f);
strokePaint.setColor(strokeColor);
shape.draw(canvas, fillPaint);
shape.draw(canvas, strokePaint);
}
}
(Late answer, hope it helps anyone struggling with shapes in appwidgets like me)
The first code you wrote is almost complete, it just lacks the call to resize(float, float) necessary before draw(Canvas, Paint). There is no need to create a custom shape object.
The SDK documentation says this for RoundRectShape and other shapes:
Draw this shape into the provided Canvas, with the provided Paint.
Before calling this, you must call resize(float, float).

How to add a stroke to ShapeDrawable

Hi
I want to create a shape drawable and fill it with gradient color with white stroke
here is my code
ShapeDrawable greenShape = new ShapeDrawable(new RectShape());
Shader shader1 = new LinearGradient(0, 0, 0, 50, new int[] {
0xFFBAF706, 0xFF4CD52F }, null, Shader.TileMode.CLAMP);
greenShape.getPaint().setShader(shader1);
greenShape.getPaint().setStrokeWidth(3);
greenShape.getPaint().setColor(Color.WHITE);
greenShape.getPaint().setStyle(Paint.Style.FILL_AND_STROKE);`
The problem is the rectangle appears with gradient fill but without stroke
The ShapeDrawable does not allow you to easily draw a stroke around it.
If you really want then this would be a nice place to look at.
OR
You could use a GradientDrawable
GradientDrawable gd = new GradientDrawable();
gd.setColor(Color.RED);
gd.setCornerRadius(10);
gd.setStroke(2, Color.WHITE);
(PS: This is given as a comment in the same page!)
It looks like this person struggled with the same issue and the only way they found was to subclass the ShapeDrawable:
Trying to draw a button: how to set a stroke color and how to "align" a gradient to the bottom without knowing the height?
<stroke
android:width="2dp"
android:color="#808080" />
try it, it will work definitely
Change the style to greenShape.getPaint().setStyle(Paint.Style.STROKE)
and
greenShape.setShaderFactory(new ShapeDrawable.ShaderFactory() {
#Override
public Shader resize(int width, int height) {
return new LinearGradient(0, 0, 0, 0, Color.WHITE, Color.WHITE, Shader.TileMode.REPEAT);

Trying to draw a button: how to set a stroke color and how to "align" a gradient to the bottom without knowing the height?

I am creating a button programmatically. It is rounded and has a gradient background, and works fine and looks nice, but I couldn't do two things I wanted:
Set a 1 pixel stroke with a given color. I tried getPaint().setStroke(), but couldn't figure how to set the stroke color. How should I do it?
Align the gradient to the bottom of the button, no matter what height it has. Is this possible?
For reference, this is the code I'm using:
Button btn = new Button(context);
btn.setPadding(7, 3, 7, 5);
btn.setTextColor(text_color);
// Create a gradient for the button. Height is hardcoded to 30 (I don't know the height beforehand).
// I wish I could set the gradient aligned to the bottom of the button.
final Shader shader = new LinearGradient(0, 0, 0, 30,
new int[] { color_1, color_2 },
null, Shader.TileMode.MIRROR);
float[] roundedCorner = new float[] { 5, 5, 5, 5, 5, 5, 5, 5 }
ShapeDrawable normal = new ShapeDrawable(new RoundRectShape(roundedCorner, null, null));
normal.getPaint().setShader(shader);
normal.setPadding(7, 3, 7, 5);
// Create a state list (I suppressed settings for pressed).
StateListDrawable state_list = new StateListDrawable();
state_list.addState(new int[] { }, normal);
btn.setBackgroundDrawable(state_list);
In terms of your first question, I struggled with this as well, and it doesn't look like there are any suitable methods within Drawables themselves (I was using ShapeDrawable) or the Paint class. However, I was able to extend ShapeDrawable and override the draw method, as below, to give the same result:
public class CustomBorderDrawable extends ShapeDrawable {
private Paint fillpaint, strokepaint;
private static final int WIDTH = 3;
public CustomBorderDrawable(Shape s) {
super(s);
fillpaint = this.getPaint();
strokepaint = new Paint(fillpaint);
strokepaint.setStyle(Paint.Style.STROKE);
strokepaint.setStrokeWidth(WIDTH);
strokepaint.setARGB(255, 0, 0, 0);
}
#Override
protected void onDraw(Shape shape, Canvas canvas, Paint fillpaint) {
shape.draw(canvas, fillpaint);
shape.draw(canvas, strokepaint);
}
public void setFillColour(int c){
fillpaint.setColor(c);
}
}
You can use a GradientDrawable with setStroke(3, Color.WHITE) method. To make rounded corners, use this:
setShape(GradientDrawable.RECTANGLE);
setCornerRadii(new float[]{2,2,2,2,2,2,2,2});
Try this....in drawable make a new xml file and set it where you want it..!
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<solid android:color="#e1e1e1" />
<stroke
android:width="2dp"
android:color="#808080" />
<corners android:radius="10dp" />
<padding
android:bottom="5dp"
android:left="5dp"
android:right="5dp"
android:top="5dp" />
</shape>

Categories

Resources