I am trying to overlay two images in my app, but they seem to crash at my canvas.setBitmap() line. What am I doing wrong?
private void test() {
Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.t);
Bitmap mBitmap2 = BitmapFactory.decodeResource(getResources(), R.drawable.tt);
Bitmap bmOverlay = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), mBitmap.getConfig());
Canvas canvas = new Canvas();
canvas.setBitmap(bmOverlay);
canvas.drawBitmap(mBitmap, new Matrix(), null);
canvas.drawBitmap(mBitmap2, new Matrix(), null);
testimage.setImageBitmap(bmOverlay);
}
You can skip the complex Canvas manipulation and do this entirely with Drawables, using LayerDrawable. You have one of two choices: You can either define it in XML then simply set the image, or you can configure a LayerDrawable dynamically in code.
Solution #1 (via XML):
Create a new Drawable XML file, let's call it layer.xml:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/t" />
<item android:drawable="#drawable/tt" />
</layer-list>
Now set the image using that Drawable:
testimage.setImageDrawable(getResources().getDrawable(R.layout.layer));
Solution #2 (dynamic):
Resources r = getResources();
Drawable[] layers = new Drawable[2];
layers[0] = r.getDrawable(R.drawable.t);
layers[1] = r.getDrawable(R.drawable.tt);
LayerDrawable layerDrawable = new LayerDrawable(layers);
testimage.setImageDrawable(layerDrawable);
(I haven't tested this code so there may be a mistake, but this general outline should work.)
ok just so you know there is a program out there that's called DroidDraw. It can help you draw objects and try them one on top of the other. I tried your solution but I had animation under the smaller image so that didn't work. But then I tried to place one image in a relative layout that's suppose to be under first and then on top of that I drew the other image that is suppose to overlay and everything worked great. So RelativeLayout, DroidDraw and you are good to go :) Simple, no any kind of jiggery pockery :) and here is a bit of code for ya:
The logo is going to be on top of shazam background image.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:id="#+id/widget30"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
>
<ImageView
android:id="#+id/widget39"
android:layout_width="219px"
android:layout_height="225px"
android:src="#drawable/shazam_bkgd"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
>
</ImageView>
<ImageView
android:id="#+id/widget37"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/shazam_logo"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
>
</ImageView>
</RelativeLayout>
You can use the code below to solve the problem or download demo here
Create two functions to handle each.
First, the canvas is drawn and the images are drawn on top of each other from point (0,0)
On button click
public void buttonMerge(View view) {
Bitmap bigImage = BitmapFactory.decodeResource(getResources(), R.drawable.img1);
Bitmap smallImage = BitmapFactory.decodeResource(getResources(), R.drawable.img2);
Bitmap mergedImages = createSingleImageFromMultipleImages(bigImage, smallImage);
img.setImageBitmap(mergedImages);
}
Function to create an overlay.
private Bitmap createSingleImageFromMultipleImages(Bitmap firstImage, Bitmap secondImage){
Bitmap result = Bitmap.createBitmap(firstImage.getWidth(), firstImage.getHeight(), firstImage.getConfig());
Canvas canvas = new Canvas(result);
canvas.drawBitmap(firstImage, 0f, 0f, null);
canvas.drawBitmap(secondImage, 10, 10, null);
return result;
}
Read more
Its a bit late answer, but it covers merging images from urls using Picasso
MergeImageView
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Build;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.widget.ImageView;
import com.squareup.picasso.Picasso;
import java.io.IOException;
import java.util.List;
public class MergeImageView extends ImageView {
private SparseArray<Bitmap> bitmaps = new SparseArray<>();
private Picasso picasso;
private final int DEFAULT_IMAGE_SIZE = 50;
private int MIN_IMAGE_SIZE = DEFAULT_IMAGE_SIZE;
private int MAX_WIDTH = DEFAULT_IMAGE_SIZE * 2, MAX_HEIGHT = DEFAULT_IMAGE_SIZE * 2;
private String picassoRequestTag = null;
public MergeImageView(Context context) {
super(context);
}
public MergeImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MergeImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public MergeImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
#Override
public boolean isInEditMode() {
return true;
}
public void clearResources() {
if (bitmaps != null) {
for (int i = 0; i < bitmaps.size(); i++)
bitmaps.get(i).recycle();
bitmaps.clear();
}
// cancel picasso requests
if (picasso != null && AppUtils.ifNotNullEmpty(picassoRequestTag))
picasso.cancelTag(picassoRequestTag);
picasso = null;
bitmaps = null;
}
public void createMergedBitmap(Context context, List<String> imageUrls, String picassoTag) {
picasso = Picasso.with(context);
int count = imageUrls.size();
picassoRequestTag = picassoTag;
boolean isEven = count % 2 == 0;
// if url size are not even make MIN_IMAGE_SIZE even
MIN_IMAGE_SIZE = DEFAULT_IMAGE_SIZE + (isEven ? count / 2 : (count / 2) + 1);
// set MAX_WIDTH and MAX_HEIGHT to twice of MIN_IMAGE_SIZE
MAX_WIDTH = MAX_HEIGHT = MIN_IMAGE_SIZE * 2;
// in case of odd urls increase MAX_HEIGHT
if (!isEven) MAX_HEIGHT = MAX_WIDTH + MIN_IMAGE_SIZE;
// create default bitmap
Bitmap bitmap = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_wallpaper),
MIN_IMAGE_SIZE, MIN_IMAGE_SIZE, false);
// change default height (wrap_content) to MAX_HEIGHT
int height = Math.round(AppUtils.convertDpToPixel(MAX_HEIGHT, context));
setMinimumHeight(height * 2);
// start AsyncTask
for (int index = 0; index < count; index++) {
// put default bitmap as a place holder
bitmaps.put(index, bitmap);
new PicassoLoadImage(index, imageUrls.get(index)).execute();
// if you want parallel execution use
// new PicassoLoadImage(index, imageUrls.get(index)).(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
private class PicassoLoadImage extends AsyncTask<String, Void, Bitmap> {
private int index = 0;
private String url;
PicassoLoadImage(int index, String url) {
this.index = index;
this.url = url;
}
#Override
protected Bitmap doInBackground(String... params) {
try {
// synchronous picasso call
return picasso.load(url).resize(MIN_IMAGE_SIZE, MIN_IMAGE_SIZE).tag(picassoRequestTag).get();
} catch (IOException e) {
}
return null;
}
#Override
protected void onPostExecute(Bitmap output) {
super.onPostExecute(output);
if (output != null)
bitmaps.put(index, output);
// create canvas
Bitmap.Config conf = Bitmap.Config.RGB_565;
Bitmap canvasBitmap = Bitmap.createBitmap(MAX_WIDTH, MAX_HEIGHT, conf);
Canvas canvas = new Canvas(canvasBitmap);
canvas.drawColor(Color.WHITE);
// if height and width are equal we have even images
boolean isEven = MAX_HEIGHT == MAX_WIDTH;
int imageSize = bitmaps.size();
int count = imageSize;
// we have odd images
if (!isEven) count = imageSize - 1;
for (int i = 0; i < count; i++) {
Bitmap bitmap = bitmaps.get(i);
canvas.drawBitmap(bitmap, bitmap.getWidth() * (i % 2), bitmap.getHeight() * (i / 2), null);
}
// if images are not even set last image width to MAX_WIDTH
if (!isEven) {
Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmaps.get(count), MAX_WIDTH, MIN_IMAGE_SIZE, false);
canvas.drawBitmap(scaledBitmap, scaledBitmap.getWidth() * (count % 2), scaledBitmap.getHeight() * (count / 2), null);
}
// set bitmap
setImageBitmap(canvasBitmap);
}
}
}
xml
<com.example.MergeImageView
android:id="#+id/iv_thumb"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
Example
List<String> urls = new ArrayList<>();
String picassoTag = null;
// add your urls
((MergeImageView)findViewById(R.id.iv_thumb)).
createMergedBitmap(MainActivity.this, urls,picassoTag);
this is my solution:
public Bitmap Blend(Bitmap topImage1, Bitmap bottomImage1, PorterDuff.Mode Type) {
Bitmap workingBitmap = Bitmap.createBitmap(topImage1);
Bitmap topImage = workingBitmap.copy(Bitmap.Config.ARGB_8888, true);
Bitmap workingBitmap2 = Bitmap.createBitmap(bottomImage1);
Bitmap bottomImage = workingBitmap2.copy(Bitmap.Config.ARGB_8888, true);
Rect dest = new Rect(0, 0, bottomImage.getWidth(), bottomImage.getHeight());
new BitmapFactory.Options().inPreferredConfig = Bitmap.Config.ARGB_8888;
bottomImage.setHasAlpha(true);
Canvas canvas = new Canvas(bottomImage);
Paint paint = new Paint();
paint.setXfermode(new PorterDuffXfermode(Type));
paint.setFilterBitmap(true);
canvas.drawBitmap(topImage, null, dest, paint);
return bottomImage;
}
usage :
imageView.setImageBitmap(Blend(topBitmap, bottomBitmap, PorterDuff.Mode.SCREEN));
or
imageView.setImageBitmap(Blend(topBitmap, bottomBitmap, PorterDuff.Mode.OVERLAY));
and the results :
Overlay mode :
Screen mode:
Related
I want to develop Rating bar like zomato android application. In which the rating bar box changes it's color according to selection. if only one box is selected then it's color is Read and gradually we select more box it became Green.
Here I attached snap of zomato android app's screen portion which shows Rating exactly I would like to develop this type of Rating and Review System.
That's a simple horizontal LinearLayout with 9 TextViews, each of them having grey as the default color. Aditionally you can create an array of strings, each string being a color code. This is the quick and dirty solution.
When clicking on a TextView, you can find out its position in the LinearLayout and color each view before it with the corresponding color code in the array, along with the selected view, and the others remain grey.
I had a similar problem once with a progress bar consisting of 10 sections, and instead of looking for a library I made something quick like this and it worked just fine.
I found solution for that we need to make Custom Rating bar Here bellow code shows Custom class of Rating bar. which full fill all requirement which mention in Question.
public class MyCustomRatingBar extends android.support.v7.widget.AppCompatRatingBar {
private int[] iconArrayActive = {
R.drawable.ic_square_sel_1,
R.drawable.ic_square_sel_2,
R.drawable.ic_square_sel_3,
R.drawable.ic_square_sel_4,
R.drawable.ic_square_sel_5,
R.drawable.ic_square_sel_6,
R.drawable.ic_square_sel_7,
R.drawable.ic_square_sel_8,
R.drawable.ic_square_sel_9
};
private int[] iconArrayInactive = {
R.drawable.ic_square_unsel,
R.drawable.ic_square_unsel,
R.drawable.ic_square_unsel,
R.drawable.ic_square_unsel,
R.drawable.ic_square_unsel,
R.drawable.ic_square_unsel,
R.drawable.ic_square_unsel,
R.drawable.ic_square_unsel,
R.drawable.ic_square_unsel
};
public MyCustomRatingBar (Context context) {
super(context);
init();
}
public MyCustomRatingBar (Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyCustomRatingBar (Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
this.setMax(9);
this.setNumStars(9);
this.setStepSize(1.0f);
this.setRating(1.0f);
}
private Bitmap getBitmapFromVectorDrawable(Context context, int drawableId) {
Drawable drawable = ContextCompat.getDrawable(context, drawableId);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
drawable = (DrawableCompat.wrap(drawable)).mutate();
}
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
#Override
protected synchronized void onDraw(Canvas canvas) {
int stars = getNumStars();
float rating = getRating();
float x = 0;
Bitmap bitmap;
Paint paint = new Paint();
int W = getWidth();
int H = getHeight();
int icon_size = (W/stars)-0;
int y_pos = (H/2)-icon_size/2;
int delta = ((H > W)?(H):(W))/(stars);
int offset = (W-(icon_size+(stars-1)*delta))/2;
for(int i = 0; i < stars; i++) {
if ((int) rating-1 >= i) {
bitmap = getBitmapFromVectorDrawable(getContext(), iconArrayActive[i]);
} else {
bitmap = getBitmapFromVectorDrawable(getContext(), iconArrayInactive[i]);
}
x = offset+(i*delta);
Bitmap scaled = Bitmap.createScaledBitmap(bitmap, icon_size, icon_size, true);
canvas.drawBitmap(scaled, x, y_pos, paint);
canvas.save();
}
}
}
I am trying to build a circle containing numerous dots that eventually will be clickable (as much as 108 dots to fill out the border of a circle).
What i have done so far is to create 108 imageviews like this:
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/circle_1"
android:src="#drawable/dot_complete"
android:layout_marginLeft="383dp"
android:layout_marginTop="214dp"
/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/circle_2"
android:src="#drawable/dot_complete"
android:layout_marginLeft="382dp"
android:layout_marginTop="214dp"
/>
<!-- And so on all the way up to 108 -->
The result looks like this
However i suspect this is a very bad method, so my question is what would be the better way to do this, considering i need to have onclickListener on each dot in order to show its info.
Thank you
I had a similar class laying around, with a small modification it can display three different types of drawables as "dots". The only thing you would have to do is to write the touch management.
Drawing 108 dots (three different types):
public class DotsView extends View {
private static final int dots = 108;
private static final int dotRadius = 20;
private Bitmap testBitmap1;
private Bitmap testBitmap2;
private Bitmap testBitmap3;
private RectF dotRect;
private Paint paint;
private int[] dotsStates = new int[dots];
public DotsView(Context context) {
super(context);
setupView(context);
}
public DotsView(Context context, AttributeSet attrs) {
super(context, attrs);
setupView(context);
}
public DotsView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setupView(context);
}
private void setupView(Context context) {
setWillNotDraw(false);
paint = new Paint();
paint.setAntiAlias(true);
test();
}
private void test() {
//THIS METHOD IS JUST A TEST THAT CHANGES THE DRAWABLES USED FOR SOME DOTS
for (int i = 2; i < 20; ++i) {
dotsStates[i] = 1;
}
for (int i = 50; i < 55; ++i) {
dotsStates[i] = 2;
}
}
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
initBitmaps();
invalidate();
}
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
destroyBitmaps();
}
private void initBitmaps() {
testBitmap1 = BitmapFactory.decodeResource(getResources(), R.drawable.test_1);
testBitmap2 = BitmapFactory.decodeResource(getResources(), R.drawable.test_2);
testBitmap3 = BitmapFactory.decodeResource(getResources(), R.drawable.test_3);
dotRect = new RectF(0, 0, dotRadius, dotRadius);
}
private boolean isBitmapValid(Bitmap bitmap) {
return bitmap != null && !bitmap.isRecycled();
}
private void destroyBitmaps() {
if (isBitmapValid(testBitmap1)) {
testBitmap1.recycle();
testBitmap1 = null;
}
if (isBitmapValid(testBitmap2)) {
testBitmap2.recycle();
testBitmap2 = null;
}
if (isBitmapValid(testBitmap3)) {
testBitmap3.recycle();
testBitmap3 = null;
}
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (isBitmapValid(testBitmap1) && isBitmapValid(testBitmap2) && isBitmapValid(testBitmap3)) {
// apply padding to canvas:
final int width = canvas.getWidth();
final int height = canvas.getHeight();
final int squareSide = Math.min(width, height);
canvas.translate(width / 2f, height / 2f); // moving to the center of the View
final float outerRadius = squareSide / 2f;
final float innerRadius = outerRadius - dotRadius;
final float angleFactor = 360f / dots;
for (int i = 0; i < dots; ++i) {
canvas.save(); // creating a "checkpoint"
canvas.rotate(angleFactor * i);
canvas.translate(innerRadius, 0); //moving to the edge of the big circle
canvas.drawBitmap(dotsStates[i] == 0 ?
testBitmap1 :
dotsStates[i] == 1 ?
testBitmap2 : testBitmap3,
null, dotRect, paint);
canvas.restore(); //restoring a "checkpoint"
}
}
}
}
Your approach is super heavyweight. I'd instead recommend making a custom View class, within which you do these things:
Override the onDraw method to draw your circles directly onto the view's Canvas
Implement an onTouchEvent listener, checking the coordinates of the touch against the positions/radii of the circles you created - thus finding the circle (if any) which was tapped
Trigger a custom event like onCircleTapped(View v, int circleId) so that the containing view/activity/fragment can handle the event properly.
You can try this librarytire view
import the barlibrary
create ChartTireView
I hope this will help you.
I'm currently using a BluringView XML Object as gotten from the BlurringView.java file (https://github.com/500px/500px-android-blur). It's basically just a custom view that blurs a sibling view that's beneath it. The problem I'm having is that I can't populate the BlurringView with other objects. Here's the code:
package com.fivehundredpx.android.blur;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.support.v8.renderscript.Allocation;
import android.support.v8.renderscript.Element;
import android.support.v8.renderscript.RenderScript;
import android.support.v8.renderscript.ScriptIntrinsicBlur;
import android.util.AttributeSet;
import android.view.View;
/**
* A custom view for presenting a dynamically blurred version of another view's content.
* <p/>
* Use {#link #setBlurredView(android.view.View)} to set up the reference to the view to be blurred.
* After that, call {#link #invalidate()} to trigger blurring whenever necessary.
*/
public class BlurringView extends View {
public BlurringView(Context context) {
this(context, null);
}
public BlurringView(Context context, AttributeSet attrs) {
super(context, attrs);
final Resources res = getResources();
final int defaultBlurRadius = res.getInteger(R.integer.default_blur_radius);
final int defaultDownsampleFactor = res.getInteger(R.integer.default_downsample_factor);
final int defaultOverlayColor = res.getColor(R.color.default_overlay_color);
initializeRenderScript(context);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PxBlurringView);
setBlurRadius(a.getInt(R.styleable.PxBlurringView_blurRadius, defaultBlurRadius));
setDownsampleFactor(a.getInt(R.styleable.PxBlurringView_downsampleFactor,
defaultDownsampleFactor));
setOverlayColor(a.getColor(R.styleable.PxBlurringView_overlayColor, defaultOverlayColor));
a.recycle();
}
public void setBlurredView(View blurredView) {
mBlurredView = blurredView;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mBlurredView != null) {
if (prepare()) {
// If the background of the blurred view is a color drawable, we use it to clear
// the blurring canvas, which ensures that edges of the child views are blurred
// as well; otherwise we clear the blurring canvas with a transparent color.
if (mBlurredView.getBackground() != null && mBlurredView.getBackground() instanceof ColorDrawable){
mBitmapToBlur.eraseColor(((ColorDrawable) mBlurredView.getBackground()).getColor());
}else {
mBitmapToBlur.eraseColor(Color.TRANSPARENT);
}
mBlurredView.draw(mBlurringCanvas);
blur();
canvas.save();
canvas.translate(mBlurredView.getX() - getX(), mBlurredView.getY() - getY());
canvas.scale(mDownsampleFactor, mDownsampleFactor);
canvas.drawBitmap(mBlurredBitmap, 0, 0, null);
canvas.restore();
}
canvas.drawColor(mOverlayColor);
}
}
public void setBlurRadius(int radius) {
mBlurScript.setRadius(radius);
}
public void setDownsampleFactor(int factor) {
if (factor <= 0) {
throw new IllegalArgumentException("Downsample factor must be greater than 0.");
}
if (mDownsampleFactor != factor) {
mDownsampleFactor = factor;
mDownsampleFactorChanged = true;
}
}
public void setOverlayColor(int color) {
mOverlayColor = color;
}
private void initializeRenderScript(Context context) {
mRenderScript = RenderScript.create(context);
mBlurScript = ScriptIntrinsicBlur.create(mRenderScript, Element.U8_4(mRenderScript));
}
protected boolean prepare() {
final int width = mBlurredView.getWidth();
final int height = mBlurredView.getHeight();
if (mBlurringCanvas == null || mDownsampleFactorChanged
|| mBlurredViewWidth != width || mBlurredViewHeight != height) {
mDownsampleFactorChanged = false;
mBlurredViewWidth = width;
mBlurredViewHeight = height;
int scaledWidth = width / mDownsampleFactor;
int scaledHeight = height / mDownsampleFactor;
// The following manipulation is to avoid some RenderScript artifacts at the edge.
scaledWidth = scaledWidth - scaledWidth % 4 + 4;
scaledHeight = scaledHeight - scaledHeight % 4 + 4;
if (mBlurredBitmap == null
|| mBlurredBitmap.getWidth() != scaledWidth
|| mBlurredBitmap.getHeight() != scaledHeight) {
mBitmapToBlur = Bitmap.createBitmap(scaledWidth, scaledHeight,
Bitmap.Config.ARGB_8888);
if (mBitmapToBlur == null) {
return false;
}
mBlurredBitmap = Bitmap.createBitmap(scaledWidth, scaledHeight,
Bitmap.Config.ARGB_8888);
if (mBlurredBitmap == null) {
return false;
}
}
mBlurringCanvas = new Canvas(mBitmapToBlur);
mBlurringCanvas.scale(1f / mDownsampleFactor, 1f / mDownsampleFactor);
mBlurInput = Allocation.createFromBitmap(mRenderScript, mBitmapToBlur,
Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
mBlurOutput = Allocation.createTyped(mRenderScript, mBlurInput.getType());
}
return true;
}
protected void blur() {
mBlurInput.copyFrom(mBitmapToBlur);
mBlurScript.setInput(mBlurInput);
mBlurScript.forEach(mBlurOutput);
mBlurOutput.copyTo(mBlurredBitmap);
}
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mRenderScript != null){
mRenderScript.destroy();
}
}
private int mDownsampleFactor;
private int mOverlayColor;
private View mBlurredView;
private int mBlurredViewWidth, mBlurredViewHeight;
private boolean mDownsampleFactorChanged;
private Bitmap mBitmapToBlur, mBlurredBitmap;
private Canvas mBlurringCanvas;
private RenderScript mRenderScript;
private ScriptIntrinsicBlur mBlurScript;
private Allocation mBlurInput, mBlurOutput;
}
Is there any way to modify the BlurringView.java class so the BlurringView xml object can be used like a RelativeView or something similar? I want to be able to have the BlurringView be the parent to other objects.
I need this, because I'm using the BlurringView together with a SlidingUpPanelLayout (https://github.com/umano/AndroidSlidingUpPanel) and the SlidingUpPanelLayout only allows two children for it to function. Thus I can't just overlay items over the BlurringView. I need the BlurringView to be their parent.
Please let me know if you need clarification.
-R
Blockquote Did you try to do an extract method of your constructor, implement the same methon in each of the three default constructors and extend from RelativeLayout?
The RelativeLayout actually have a onDraw method, maybe isn't being called because you didn't invoke the method setWillNotDraw(false), try using that method to trigger the onDraw or use an invalidate() at the end of the constructors.
#astinx answered this question.
All I had to do was change the BlurringView class to extend a RelativeLayout instead of a View. I then called the setWillNotDraw(false) method as well as the invalidate() method in the constructor and now I'm able to populate the BlurringView with children! Magic.
-R
I am a programmer with a Windows background and I am new to Java and Android stuff.
I want to create a widget (not an app) which displays a chart. After a long research I know I can do this with Canvas, imageviews and Bitmaps. The canvas which I paint on should be the same as the Widget Size.
How do I know the widget size (or imageview size) so that I can supply it to the function?
Bitmap.createBitmap(width_xx, height_yy, Config.ARGB_8888);
Code Snippet:
In the timer run method:
#Override
public void run() {
Bitmap bitmap = Bitmap.createBitmap(??, ??, Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
// Create a new paint
Paint p = new Paint();
p.setAntiAlias(true);
p.setStrokeWidth(1);
// Draw circle
// Here I can use the width and height to scale the circle
canvas.drawCircle(50, 50, 7, p);
remoteViews.setImageViewBitmap(R.id.imageView, bitmap);
From what I've learnt, you can only calculate widget dimensions on Android 4.1+.
When on a lower API, you'll have to use static dimensions.
About widget dimensions: App Widget Design Guidelines
int w = DEFAULT_WIDTH, h = DEFAULT_HEIGHT;
if ( Build.VERSION.SDK_INT >= 16 ) {
Bundle options = appWidgetManager.getAppWidgetOptions(widgetId);
int maxW = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH);
int maxH = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT);
int minW = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH);
int minH = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT);
if ( context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ) {
w = maxW;
h = minH;
} else {
w = minW;
h = maxH;
}
}
Have a look at the method:
public void onAppWidgetOptionsChanged (Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions)
It will be called each time you start/resize the widget.
Getting the widget width/height can be done as follows:
newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH)
newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH)
newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT)
newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT)
I am currently using this:
private void run() {
int width = 400, height = 400;
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bitmap);
Paint p = new Paint();
p.setColor(Color.WHITE);
p.setStyle(Paint.Style.STROKE);
p.setStrokeWidth(1);
p.setAntiAlias(true);
c.drawCircle(width/2, height/2, radius, p);
remoteViews.setImageViewBitmap(R.id.imageView, bitmap);
ComponentName clockWidget = new ComponentName(context,
Clock_22_analog.class);
AppWidgetManager appWidgetManager = AppWidgetManager
.getInstance(context);
appWidgetManager.updateAppWidget(clockWidget, remoteViews);
}
You can use this
Bitmap image1, image2;
Bitmap bitmap = Bitmap.createBitmap(image1.getWidth(), image1.getHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bitmap);
You can create a custom widget and set the size of wight on its onMeasure() method. And also save the size at that time so that you can use it further for image creation...
I've not worked on Widgets, but I have some experience getting ImageView's size.
Here is some code I use:
public class ViewSizes {
public int width;
public int height;
public boolean isEmpty() {
boolean result = false;
if (0 >= width || 0 >= height) {
result = true;
}
return result;
}
}
That's just a dummy class containing the size parameters.
public static ViewSizes getSizes(View view) {
ViewSizes sizes = new ViewSizes();
sizes.width = view.getWidth();
sizes.height = view.getHeight();
if (sizes.isEmpty()) {
LayoutParams params = view.getLayoutParams();
if (null != params) {
int widthSpec = View.MeasureSpec.makeMeasureSpec(params.width, View.MeasureSpec.AT_MOST);
int heightSpec = View.MeasureSpec.makeMeasureSpec(params.height, View.MeasureSpec.AT_MOST);
view.measure(widthSpec, heightSpec);
}
sizes.width = view.getMeasuredWidth();
sizes.height = view.getMeasuredHeight();
}
return sizes;
}
This method calculates the width forcing a measure cycle if such has not already happened.
public static boolean loadPhoto(ImageView view, String url, float aspectRatio) {
boolean processed = false;
ViewSizes sizes = ViewsUtils.getSizes(view);
if (!sizes.isEmpty()) {
int width = sizes.width - 2;
int height = sizes.height - 2;
if (ASPECT_RATIO_UNDEFINED != aspectRatio) {
if (height * aspectRatio > width) {
height = (int) (width / aspectRatio);
} else if (height * aspectRatio < width) {
width = (int) (height * aspectRatio);
}
}
// Do you bitmap processing here
processed = true;
}
return processed;
}
This one is probably useless for you. I give just as an example - I have an ImageView and image URL, which should be parametrized with image and height.
public class PhotoLayoutListener implements OnGlobalLayoutListener {
private ImageView view;
private String url;
private float aspectRatio;
public PhotoLayoutListener(ImageView view, String url, float aspectRatio) {
this.view = view;
this.url = url;
this.aspectRatio = aspectRatio;
}
boolean handled = false;
#Override
public void onGlobalLayout() {
if (!handled) {
PhotoUtils.loadPhoto(view, url, aspectRatio);
handled = true;
}
ViewTreeObserver viewTreeObserver = view.getViewTreeObserver();
if (viewTreeObserver.isAlive()) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
removeLayoutListenerPre16(viewTreeObserver, this);
} else {
removeLayoutListenerPost16(viewTreeObserver, this);
}
}
}
#SuppressWarnings("deprecation")
private void removeLayoutListenerPre16(ViewTreeObserver observer, OnGlobalLayoutListener listener){
observer.removeGlobalOnLayoutListener(listener);
}
#TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private void removeLayoutListenerPost16(ViewTreeObserver observer, OnGlobalLayoutListener listener){
observer.removeOnGlobalLayoutListener(listener);
}
}
This is just a layout listener - I want to process the image loading once the layout phase has finished.
public static void setImage(ImageView view, String url, boolean forceLayoutLoading, float aspectRatio) {
if (null != view && null != url) {
final ViewTreeObserver viewTreeObserver = view.getViewTreeObserver();
if (forceLayoutLoading || !PhotoUtils.loadPhoto(view, url, aspectRatio)) {
if (viewTreeObserver.isAlive()) {
viewTreeObserver.addOnGlobalLayoutListener(new PhotoLayoutListener(view, url, aspectRatio));
}
}
}
}
This is the method I actually call. I give it the view and URL. The methods takes care of loading - if it can determine the view's size it starts loading immediately. Otherwise it just assigns a layout listener and start the loading process once the layout is finished.
You could strip away some parameters - forceLoading / aspectRatio should be irrelevant for you. After that change the PhotoUtils.loadPhoto method in order to create the bitmap with the width / height it has calculated.
Like Julian told us, you can get them like that with a bitmap of your image:
int width = bitmap.getWidth();
int height = bitmap.getHeight();
How do I implement background scrolling with a gridview? If it sounds vague, I mean like implementing a bookshelf using a gridview where the shelf image is attached to an item in the gridview.
It took me forever to figure this out, so for everybody trying to do this, here's the code from my e-book reader.
It's based on Shelves by Romain Guy so he deserves the credit for the original code.
package net.nightwhistler.pageturner.view;
import net.nightwhistler.pageturner.R;
import net.nightwhistler.pageturner.library.LibraryBook;
import net.nightwhistler.pageturner.library.QueryResult;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.widget.GridView;
public class BookCaseView extends GridView {
private Bitmap background;
private int mShelfWidth;
private int mShelfHeight;
private QueryResult<LibraryBook> result;
private LibraryBook selectedBook;
public BookCaseView(Context context, AttributeSet attributes) {
super(context, attributes);
this.setFocusableInTouchMode(true);
this.setClickable(false);
final Bitmap shelfBackground = BitmapFactory.decodeResource(context.getResources(),
R.drawable.shelf_single);
setBackground(shelfBackground);
this.setFocusable(true);
}
public void setBackground(Bitmap background) {
this.background = background;
mShelfWidth = background.getWidth();
mShelfHeight = background.getHeight();
}
protected void onClick( int bookIndex ) {
LibraryBook book = this.result.getItemAt(bookIndex);
this.selectedBook = book;
invalidate();
}
#Override
protected void dispatchDraw(Canvas canvas) {
final int count = getChildCount();
final int top = count > 0 ? getChildAt(0).getTop() : 0;
final int shelfWidth = mShelfWidth;
final int shelfHeight = mShelfHeight;
final int width = getWidth();
final int height = getHeight();
final Bitmap background = this.background;
for (int x = 0; x < width; x += shelfWidth) {
for (int y = top; y < height; y += shelfHeight) {
canvas.drawBitmap(background, x, y, null);
}
//This draws the top pixels of the shelf above the current one
Rect source = new Rect(0, mShelfHeight - top, mShelfWidth, mShelfHeight);
Rect dest = new Rect(x, 0, x + mShelfWidth, top );
canvas.drawBitmap(background, source, dest, null);
}
super.dispatchDraw(canvas);
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ( keyCode == KeyEvent.KEYCODE_BACK && this.selectedBook != null ) {
this.selectedBook = null;
invalidate();
return true;
}
return false;
}
}
What I did was to split my background image in n gridview columns and in my gridview getView method add the view background according to the position in the grid.
It worked perfectly.
If you want the code just ask.
My previous answer only adds the background but doesn't let it scroll with the items. what you wan is NightWhistler's answer :)
Sorry for misinterpreting the question.