loading Image in RecyclerView Adapter using volley [duplicate] - android

I'm trying to draw on an ImageViewTouch, a library which enables pinch zooming. I'm able to draw over the image using Canvas, but when I zoom the image, the drawing disappears.
For this, I'm trying to convert the view to a bitmap and set theImageBitmap for this same view. Here's the code:
mImage.setDrawPath(true);
mImage.setImageBitmap(loadBitmapFromView(mImage));
public static Bitmap loadBitmapFromView(View v) {
Bitmap b = Bitmap.createBitmap( v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
v.layout(0, 0, v.getWidth(), v.getHeight());
v.draw(c);
return b;
}
When I do this, I get the following log error:
07-11 21:13:41.567: E/AndroidRuntime(20056): java.lang.IllegalArgumentException: width and height must be > 0
07-11 21:13:41.567: E/AndroidRuntime(20056): at android.graphics.Bitmap.createBitmap(Bitmap.java:638)
07-11 21:13:41.567: E/AndroidRuntime(20056): at android.graphics.Bitmap.createBitmap(Bitmap.java:620)
If I remove the loadBitmapFromView call the drawing normally appears over the image. When I try to do any interaction with the image (like zooming in or out), the drawing disappears, remaing only the background image, which is a picture.
--- EDIT ---
Here's some more code placed after the loadBitmapFromView call. The case is: I have a radio group listenner and when I check some radio button, I have to load the image and draw some possibles drawings over it.. then I'm trying to convert everything (the image and the drawings) into only one bitmap.
Here's the ohter part of the code:
bitmap = BitmapUtils.decodeSampledBitmapFromResource(root + DefinesAndroid.CAMINHO_SHOPPINGS_SDCARD + nomeImagemAtual, size.x, size.y);
mImage.setImageBitmap(bitmap);
After that, I draw everything I have to draw and try to convert the view to bitmap using the loadImageBitmap method I have shown.
the decodeSampledBitmapFromResource method I got from this link on android developers http://developer.android.com/training/displaying-bitmaps/load-bitmap.html

I finally figured out a solution for my problem.
I'm using the post method of the View, which will be executed only after the view measuring and layouting, this way getWidth() and getHeight() returns the actual width and height.
Here's the code sample:
mImage.post(new Runnable() {
#Override
public void run() {
mImage.setImageBitmap(loadBitmapFromView(mImage));
}
});
Hope it also helps someone else :)

If everything else is correct you are executing your code too early.
The view's layout has not yet been measured by Android. Try executing in OnResume just to see if this is your problem.
Cheers!

new Handler().postDelayed(new Runnable() {
#Override
public void run() {
loadBitmapFromView(mImage);
}
}, 1000);

java.lang.IllegalArgumentException: width and height must be > 0 is because in your Bitmap.createBitmap() call v.getLayoutParams().width or v.getLayoutParams().height is 0. Probably the LayoutParams are wrongly set in mImage.
Update: setLayoutParams() for the mImage before using createBitmap(). Something like this:
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(30, 30);
mImage.setLayoutParams(layoutParams);

In my case, I forgot to set orientation to vertical for parent LinearLayout and the default value of horizontal has been set, so I set it and my problem gone...
android:orientation="vertical"

I'm not sure if it relates to this specific question , but I had the same error and I solved it with getting a image source , in the layout xml file , from drawable instead of from mipmap (of course I had to put the image there before).

Related

setPadding on ImageView doesnt work after setLayoutParams

I'm making a custom View thats derived from an ImageViewand I control where the image has to be within this ImageView using padding.
I have set OnClickListener on my custom ImageView that resizes it:
image.setOnClickListener(new ImageView.OnClickListener(){
#Override
public void onClick(View v) {
image.resize_image();
}
});
and this is how this function is looking like
public void resize_image(){
ViewGroup.LayoutParams params = getLayoutParams();
params.height = new_heigth;
params.width = new_width;
setLayoutParams(params);
}
After this resizing is done I don't want my displayed image to change size (only the custom ImageView is changing size so I can draw an extra stuff around this image) within my custom ImageView so inside onDraw(Canvas) member function I set the new padding
class custom_ImageView extends ImageView{
//...
#Override
protected void onDraw(Canvas canvas) {
//...
setPadding(new_left_padding, new_top_padding, new_right_padding, new_bottom_padding);
//...
}
//...
}
Result is that width and heigth are changed like I wanted but my displayed image is neither in the right position or size.
Interesting this is that if I add an extra line of invalidate(); in the end of my resize_image() and I click on my custom_ImageView twice - on the 2nd click image draws itself in right size and position like I wanted.
Can anyone tell me why this is happening?
I kind of worked around this by not using ImageView at all but just drawing image where it needs to be by using Canvas.drawBitmap(Bitmap, RectF, RectF, Paint)
This way I don't have to specify images location using setPadding within onDraw, but I can do it simply by specifying position using RectF.

Why editing LayoutParams size doesn't have the effect of a canvas size

I am working on slide menu view which extends SurfaceView but when I try to change size of the view a canvas does not change.
For debug purpose, I am changing size of the view calling method:
public void changeSize() {
width += 10;
getLayoutParams().width = width;
this.setLayoutParams(getLayoutParams());
}
Then in a draw function I paint the canvas white and draw red line diagonally across the view:
public void draw() throws Exception {
SurfaceHolder surfaceHolder = getHolder();
if (surfaceHolder.getSurface().isValid()) {
Canvas canvas = surfaceHolder.lockCanvas();
Log.i(TAG, "draw > canvas size: " + canvas.getWidth() + " " + canvas.getHeight() );
paint.setColor(Color.rgb(255,0,0));
paint.setStrokeWidth(5);
canvas.drawColor(Color.rgb(255, 255, 255));
canvas.drawLine(0, getLayoutParams().height, getLayoutParams().width, 0, paint);
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
What I see is a white rectangle with fixed size and part of red line:
demo.
Also, when I call this.getWidth() I get unchanged width.
Why view size is not changing? Is it the same reason that the canvas is not changing? What can I do to fix it?
I found reason for myself.
I did not mention about something - that I thought was not important - I called changeSize() via other thread than created the view and this is not allowed because: Only the original thread that created a view hierarchy can touch its views. And this problem was many time solved, e.g. here
I could use Activity.runOnUiThread() method but I did not want to pass the Activity to the view so I use View.post() method in the changeSize() like this:
Runnable changeParams = new Runnable() {
#Override
public void run() {
getLayoutParams().width = width;
setLayoutParams(getLayoutParams());
}
};
this.post(changeParams);
Update:
Maybe I do not know about proper way of using the UI Thread but whatever I tried I can not change view parameters smoothly.
Some workarounds to implement a slide menu:
Do [Android navigation Drawer][4] -- you can custiomize it with restictions e.g. you can not do the navigation drawer moving from top.
Use [Android animations][5] -- with it you can move or scale a view but can not resizing it.
I can not put more than 2 links with my reputation:
(4): developer.android.com/training/implementing-navigation/nav-drawer.html
(5): developer.android.com/training/animation/index.html
By doing getLayoutParams().width = width; you are changing layout params of the View. But you are performing drawing on a Canvas that owns SurfaceHolder, and not the one an ordinary View will provide you.
So, in order to change the size of the SurfaceView, you have to interact with SurfaceHolder:
surfaceView.getHolder().setFixedSize(width, height);

Androidplot - when does the gridRect is measured?

I'm using androidplot to display a fixed-sized graph, which I've setted up a BitmapShader to match each Range interval and I need to set this shader to be always displayed on the graph, since it's beginning.
My problem is:
I can't intialize the graph with this shader (I've tested it using as base the DemoApp and the shader is working properly). Every time I try to get the GridRect using the method getGridRect() it returns null, no matter where I call this function during the activity creation. I can only set the shadder after the activity is created, but only with a button or something like it.
I searched through the entire source code but could not find where this measure occurs during the activity's lifecycle.
Unfortunately, I was unable the proper way of getting the gridrect mesured during it's creatiion, but I've found a way around.
I was able to define the graph height by getting the XYPlot view-height and subtract the graph top and bottom padding.
A snippet from my code:
#Override
protected void onCreate(Bundle savedInstanceState) {
...
mPlot.getGraphWidget().setPaddingBottom(20);
mPlot.getGraphWidget().setPaddingTop(20);
//Added a ViewTreeObserver to be sure when the Plot was measured.
mPlot.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
mPlot.getViewTreeObserver().removeOnGlobalLayoutListener(this);
//Avoid the factory trying to scale bitmap according to Display density
Options options = new BitmapFactory.Options();
options.inScaled = false;
Bitmap bm = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.chartbackground, options), 1, (int) mPlot.getHeight() - 40, false);
BitmapShader backgroundShader = new BitmapShader(bm, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
Matrix shaderMatrix = new Matrix();
//This matrix references always stayed the same even if the plot changed its size.
shaderMatrix.setTranslate(49.6875f, 30.75f);
backgroundShader.setLocalMatrix(shaderMatrix);
mPlot.getGraphWidget().getGridBackgroundPaint().setShader(backgroundShader);
//Setting the background to be a little bit translucid.
mPlot.getGraphWidget().getGridBackgroundPaint().setAlpha(90);
}
});
...
}

getDrawingCache is not updated

I'm calling getDrawingCache in the onDraw function. The problem is that it contains the changes to the canvas only in the first time, and after that, it's not updated at all with the new changes. Here's my code:
paintAction.draw(canvas);
if (paintAction.isPermanentChange())
{
Bitmap partialBitmap=getDrawingCache();
int numColored=0;
for (int index1=0;index1<partialBitmap.getWidth();index1++)
{
for (int index2=0;index2<partialBitmap.getHeight();index2++)
{
if (partialBitmap.getPixel(index1,index2)==0xFF000000)
numColored++;
}
}
Log.i("PaintDroid","Bitmap pixels: " + numColored);
int areaWidth=partialBitmap.getWidth()-SCROLLBAR_SIZE;
int areaHeight=partialBitmap.getHeight()-SCROLLBAR_SIZE;
int[] pixels=new int[areaWidth*areaHeight];
partialBitmap.getPixels(pixels,0,areaWidth,0,0,areaWidth,
areaHeight);
numColored=0;
for (int index=0;index<pixels.length;index++)
if (pixels[index]==0xFF000000) numColored++;
Log.i("PaintDroid","Pixels: " + numColored);
(setDrawingCache(true) is called when the view is created, because if I call it from onDraw, getDrawingCache will return null.)
As can be seen, I'm counting the number of black pixels, both by traversing the bitmap and getting the values in an array, and as I said, I get the number I expected for in the first time, but after that, it was supposed to increase, yet doesn't change at all!
Does anybody have an idea what's wrong?
Thanks.
I solved it. The problem was that I called setDrawingCacheEnabled(true) before the last draw operation on the canvas in onDraw. It must be called after you finished drawing, otherwise you won't get correct results.
Just to clarify, the problem here is that the View's drawing cache was not invalidated before the second time you call getDrawingCache().
In order for the drawing cache to be refreshed it must be invalidated and the order of call to the methods should be as follows:
public Bitmap renderView(View view) {
view.setDrawingCacheEnabled(true)
Bitmap bitmap = view.getDrawingCache();
view.setDrawingCacheEnabled(false)
return bitmap;
}

Clearing canvas with Canvas.drawColor()

i'm attempting to change the background image of a custom View with some success. the image will change but the problem is that i still see traces of the old image. when i attempt to clear the canvas before drawing the new image, it doesn't appear to work. i create a bitmap to store the image. when changing the image, i call Canvas.drawColor() before drawing the new image but the old image persists. i've tried drawColor(0), drawColor(Color.BLACK), c.drawColor(0, PorterDuff.Mode.CLEAR), and none of the above works. as such, i had to post this for review from more experienced minds than mine.
the actual code is as follows:
private int bgnd;
private boolean switching;
public void setBgnd(int incoming){
switching = true;
switch (incoming){
case R.drawable.image1:
bgnd = incoming;
this.invalidate();
break;
case R.drawable.image2:
bgnd = incoming;
this.invalidate();
break;
}
}
protected void onDraw(Canvas c){
if(switching == true){
Bitmap b = BitmapFactory.decodeResource(getResources(), bgnd);
c.drawColor(0, PorterDuff.Mode.CLEAR);
c.drawBitmap(b, 0, 0, null);
switching = false;
}else{
Bitmap b = BitmapFactory.decodeResource(getResources(), bgnd);
c.drawBitmap(b, 0, 0, null);
}
}
Just like you, I struggled how to clear a top layer/surfaceview in my multiple layer/surfaceview app. After 2 days searching and coding, I found out my own way and this is how I cleared a canvas before drawing, you can use it when having multiple layers/surfaceviews. The background layer will not be covered with black, that is the trick.
Paint paint = new Paint();
paint.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
canvas.drawPaint(paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC));
// start your own drawing
You can use Canvas's method drawRGB.
Do you not need to also call invalidate() from within your onDraw method, so that changes made in that onDraw are updated on the screen?
The invalidate() in your switch will invoke your onDraw after you call setBgnd, but there's nothing saying to redraw after you've made changes to the Canvas.
I just meet this problem.
I solve it by repeating “..Drawxxx();Post();” for at least 3 times,it works well.
I guess ,“double buffering” is the reason,sometimes it is “trible buffering”.we need to repeat our drawing to make sure that each “buffer” is updated..

Categories

Resources