How to blur background images in Android - java

What is the best way to blur background images like the image below? I saw some code and libraries but their are a couple of years old or like BlurBehind library, but it doesn't give the same effect.

The easiest way to do that is use a library. Take a look at this one: https://github.com/wasabeef/Blurry
With the library you only need to do this:
Blurry.with(context)
.radius(10)
.sampling(8)
.color(Color.argb(66, 255, 255, 0))
.async()
.onto(rootView);

This is an easy way to blur Images Efficiently with Android's RenderScript that I found on this article
Create a Class called BlurBuilder
public class BlurBuilder {
private static final float BITMAP_SCALE = 0.4f;
private static final float BLUR_RADIUS = 7.5f;
public static Bitmap blur(Context context, Bitmap image) {
int width = Math.round(image.getWidth() * BITMAP_SCALE);
int height = Math.round(image.getHeight() * BITMAP_SCALE);
Bitmap inputBitmap = Bitmap.createScaledBitmap(image, width, height, false);
Bitmap outputBitmap = Bitmap.createBitmap(inputBitmap);
RenderScript rs = RenderScript.create(context);
ScriptIntrinsicBlur theIntrinsic = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
Allocation tmpIn = Allocation.createFromBitmap(rs, inputBitmap);
Allocation tmpOut = Allocation.createFromBitmap(rs, outputBitmap);
theIntrinsic.setRadius(BLUR_RADIUS);
theIntrinsic.setInput(tmpIn);
theIntrinsic.forEach(tmpOut);
tmpOut.copyTo(outputBitmap);
return outputBitmap;
}
}
Copy any image to your drawable folder
Use BlurBuilder in your activity like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_login);
mContainerView = (LinearLayout) findViewById(R.id.container);
Bitmap originalBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.background);
Bitmap blurredBitmap = BlurBuilder.blur( this, originalBitmap );
mContainerView.setBackground(new BitmapDrawable(getResources(), blurredBitmap));
Renderscript is included into support v8 enabling this answer down to api 8. To enable it using gradle include these lines into your gradle file (from this answer)
defaultConfig {
...
renderscriptTargetApi *your target api*
renderscriptSupportModeEnabled true
}
Result

You can use:
Glide.with(getContext()).load(R.mipmap.bg)
.apply(bitmapTransform(new BlurTransformation(22)))
.into((ImageView) view.findViewById(R.id.imBg));
This requires the following addition to your build.gradle file:
implementation 'jp.wasabeef:glide-transformations:4.0.0'

The simplest way to achieve this is given below,
I)
Glide.with(context.getApplicationContext())
.load(Your Path)
.override(15, 15) // (change according to your wish)
.error(R.drawable.placeholder)
.into(image.score);
else you can follow the code below..
II)
1.Create a class.(Code is given below)
public class BlurTransformation extends BitmapTransformation {
private RenderScript rs;
public BlurTransformation(Context context) {
super( context );
rs = RenderScript.create( context );
}
#Override
protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
Bitmap blurredBitmap = toTransform.copy( Bitmap.Config.ARGB_8888, true );
// Allocate memory for Renderscript to work with
Allocation input = Allocation.createFromBitmap(
rs,
blurredBitmap,
Allocation.MipmapControl.MIPMAP_FULL,
Allocation.USAGE_SHARED
);
Allocation output = Allocation.createTyped(rs, input.getType());
// Load up an instance of the specific script that we want to use.
ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
script.setInput(input);
// Set the blur radius
script.setRadius(10);
// Start the ScriptIntrinisicBlur
script.forEach(output);
// Copy the output to the blurred bitmap
output.copyTo(blurredBitmap);
toTransform.recycle();
return blurredBitmap;
}
#Override
public String getId() {
return "blur";
}
}
2.Set image to ImageView using Glide.
eg:
Glide.with(this)
.load(expertViewDetailsModel.expert.image)
.asBitmap()
.transform(new BlurTransformation(this))
.into(ivBackground);

Android 12, Preview 1 comes with built-in blur feature. We need not depend on external library now. Here is the code
imageView.setRenderEffect(
RenderEffect.createBlurEffect(
20.0f, 20.0f, SHADER_TITLE_MODE
)
)

Works only on Android 12 as of now so is not a universal solution yet
To blur a image
1 Set your target SDK and compile SDK to Android S in build.gradle
2.Use Render Effect
3.set blur as follows
your_view.setRenderEffect(
RenderEffect.createBlurEffect(
30f, //radius X
30f, //Radius Y
Shader.TileMode.[X]// X=CLAMP,DECAL,MIRROR,REPEAT
)
4.The 4 types of blend mode are
CLAMP- Replicate the edge color if the shader draws outside of its original bounds
DECAL- Render the shader's image pixels only within its original bounds
MIRROR- Repeat the shader's image horizontally and vertically, alternating mirror images so that adjacent images always seam.
REPEAT - Repeat the shader's image horizontally and vertically.

This worked for me. Tested on Android 9 and 12. Use Glide library to shrink the bitmap.
// Glide
implementation 'com.github.bumptech.glide:glide:4.13.0'
kapt 'com.github.bumptech.glide:compiler:4.13.0'
Glide.with(context).asBitmap().load(favorite.coverImage).into(object : CustomTarget<Bitmap>(2, 2) {
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
ivContentHolder.setImageDrawable(BitmapDrawable(itemBinding.root.context.resources, resource))
}
override fun onLoadCleared(placeholder: Drawable?) {
ivContentHolder.setImageDrawable(null)
}
CustomTarget(2, 2) is the trick. The lower the value the more the blur effect. Basically its used to shrink the image size. Then all you have to do is set the shrunk bitmap to your imageView. And most important is to set ScaleType of the imageView to CenterCrop.
<ImageView
android:id="#+id/iv_content_holder"
android:layout_width="match_parent"
android:layout_height="96dp"
android:scaleType="centerCrop"
android:src="#color/purple_700"
app:layout_constraintBottom_toBottomOf="parent" />
The result will look something like this. Blur Effect Demo

this might not be the most efficient solution but I had to use it since the wasabeef/Blurry library didn't work for me. this could be handy if you intend to have some getting-blurry animation:
1- you need to have 2 versions of the picture, normal one and the blurry one u make with photoshop or whatever
2- set the images fit on each other in your xml, then one of them could be seen and that's the upper one
3- set fadeout animation on the upper one:
final Animation fadeOut = new AlphaAnimation(1, 0);
fadeOut.setInterpolator(new AccelerateInterpolator());
fadeOut.setDuration(1000);
fadeOut.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {}
#Override
public void onAnimationEnd(Animation animation) {upperone.setVisibility(View.GONE);}
#Override
public void onAnimationRepeat(Animation animation) {}
});
upperone.startAnimation(fadeOut);

you can use Glide for load and transform into blur image,
1) for only one view,
val requestOptions = RequestOptions()
requestOptions.transform(BlurTransformation(50)) // 0-100
Glide.with(applicationContext).setDefaultRequestOptions(requestOptions)
.load(imageUrl).into(view)
2) if you are using the adapter to load an image in the item, you should write your code in the if-else block, otherwise, it will make all your images blurry.
if(isBlure){
val requestOptions = RequestOptions()
requestOptions.transform(BlurTransformation(50))
Glide.with(applicationContext).setDefaultRequestOptions(requestOptions)
.load(imageUrl).into(view )
}else{
val requestOptions = RequestOptions()
Glide.with(applicationContext).setDefaultRequestOptions(requestOptions).load(imageUrl).into(view)
}

Android 12 (Api level 31) has new Theme parameters to apply for windows to blur background:
<style name="BlurryTheme" parent="...">
<item name="android:windowBackgroundBlurRadius">30dp</item>
<item name="android:windowBlurBehindEnabled">true</item>
<item name="android:windowBlurBehindRadius">10dp</item>
</style>
And also new API for View to apply blur effect android.view.View#setRenderEffect:
imageView.setRenderEffect(
RenderEffect.createBlurEffect(
20.0f, 20.0f, Shader.TileMode.CLAMP
)
)

You can have a view with Background color as black and set alpha for the view as 0.7 or whatever as per your requirement.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/onboardingimg1">
<View
android:id="#+id/opacityFilter"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/black"
android:layout_alignParentBottom="true"
android:alpha="0.7">
</View>
</RelativeLayout>

Try below code..
Put This Code in On Create..
if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy =
new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
Url="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTIur0ueOsmVmFVmAA-SxcCT7bTodZb3eCNbiShIiP9qWCWk3mDfw";
// Picasso.with(getContext()).load(Url).into(img_profile);
// Picasso.with(getContext()).load(Url).into(img_c_profile);
bitmap=getBitmapFromURL(Url);
Bitmap blurred = blurRenderScript(bitmap, 12);//second parametre is radius
img_profile.setImageBitmap(blurred);
Create Below Methods.. Just Copy Past..
public static Bitmap getBitmapFromURL(String src) {
try {
URL url = new URL(src);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
Bitmap myBitmap = BitmapFactory.decodeStream(input);
return myBitmap;
} catch (IOException e) {
// Log exception
return null;
}
}
#SuppressLint("NewApi")
private Bitmap blurRenderScript(Bitmap smallBitmap, int radius) {
try {
smallBitmap = RGB565toARGB888(smallBitmap);
} catch (Exception e) {
e.printStackTrace();
}
Bitmap bitmap = Bitmap.createBitmap(
smallBitmap.getWidth(), smallBitmap.getHeight(),
Bitmap.Config.ARGB_8888);
RenderScript renderScript = RenderScript.create(getActivity());
Allocation blurInput = Allocation.createFromBitmap(renderScript, smallBitmap);
Allocation blurOutput = Allocation.createFromBitmap(renderScript, bitmap);
ScriptIntrinsicBlur blur = ScriptIntrinsicBlur.create(renderScript,
Element.U8_4(renderScript));
blur.setInput(blurInput);
blur.setRadius(radius); // radius must be 0 < r <= 25
blur.forEach(blurOutput);
blurOutput.copyTo(bitmap);
renderScript.destroy();
return bitmap;
}
private Bitmap RGB565toARGB888(Bitmap img) throws Exception {
int numPixels = img.getWidth() * img.getHeight();
int[] pixels = new int[numPixels];
//Get JPEG pixels. Each int is the color values for one pixel.
img.getPixels(pixels, 0, img.getWidth(), 0, 0, img.getWidth(), img.getHeight());
//Create a Bitmap of the appropriate format.
Bitmap result = Bitmap.createBitmap(img.getWidth(), img.getHeight(), Bitmap.Config.ARGB_8888);
//Set RGB pixels.
result.setPixels(pixels, 0, result.getWidth(), 0, 0, result.getWidth(), result.getHeight());
return result;
}

This might be a very late reply but I hope it helps someone.
You can use third party libs such as RenderScript/Blurry/etc.
If you do not want to use any third party libs, you can do the below using alpha(setting alpha to 0 means complete blur and 1 means same as existing).
Note(If you are using point 2) : While setting alpha to the background, it will blur the whole layout. To avoid this, create a new xml containing drawable and set alpha here to 0.5 (or value of your wish) and use this drawable name (name of file) as the background.
For example, use it as below (say file name is bgndblur.xml):
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:shape="rectangle"
android:src="#drawable/registerscreenbackground"
android:alpha="0.5">
Use the below in your layout :
<....
android:background="#drawable/bgndblur">
Hope this helped.

You can quickly get to blur effect by doing the following.
// Add this to build.gradle app //
Compile ' com.github.jgabrielfreitas:BlurImageView:1.0.1 '
// Add to XML
<com.jgbrielfreitas.core.BlurImageView
android:id="#+id/iv_blur_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
//Add this to java
Import com.jgabrielfreitas.core.BlueImageView;
// Under public class *activity name * //
BlurImageView myBlurImage;
// Under Oncreate//
myBlurImage = (ImageView) findViewById(R.id.iv_blur_image)
MyBlurImage.setBlue(5)
I hope that helps someone

Related

Android RotateDrawable on SVG produces jagged edges

I'm trying to visualize a rotating object on an Android 9 device by programmatically rotating a vector drawable, created from a .svg file using the New->Vector Asset method. The rotation of the object should follow the changes of some external property, instead of a predefined animation.
When a vector image is drawn on an ImageView as a VectorDrawable, the image produced has smooth edges as it should, but when the image is rotated programmatically using a RotateDrawable, the edges become jagged, as if the image was treated as a bitmap, and not redrawn as vector graphics.
The image below illustrates this problem:
According to the VectorDrawable documentation, a bitmap cache is created for each vector asset when it is first loaded, but is there a possibility to force the re-rendering when the image is rotated?
Below is some sample code used to create the effect.
Drawable class:
public class MyDrawable extends Drawable implements Drawable.Callback, Runnable {
#Override
public void draw(Canvas canvas)
{
VectorDrawable vectorDrawable = (VectorDrawable)mainActivity.getResources().getDrawable(R.drawable.test_drawable, mainActivity.getTheme());
vectorDrawable.setBounds(canvas.getClipBounds());
vectorDrawable.draw(canvas); // This looks OK
RotateDrawable rotator = new RotateDrawable();
rotator.setBounds(canvas.getClipBounds());
rotator.setLevel(1000);
rotator.setDrawable(vectorDrawable.mutate());
rotator.draw(canvas); // Jagged edges
}
}
Used in an ImageView in a Fragment:
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
final ImageView testView = (ImageView)getView().findViewById(R.id.test_view);
testView.setImageDrawable(new MyDrawable());
}
There seems to be no built-in support currently in Android for what I'm trying to achieve, but I found at least one working solution, which is to use the third-party AndroidSVG library and modify the .svg upper-most group <g> element directly to include a transformation:
#Override
public void draw(Canvas canvas)
{
try {
String svgString = // Your .svg file as plaintext
svgString = svgString.replaceFirst("<g>", "<g transform=\"rotate(" + angle + ", " + pivotX + " , " + pivotY + ")\">");
SVG svg = SVG.getFromString(svgString);
svg.renderToCanvas(canvas);
// ...
}
catch (SVGParseException svgpe){}
}

Why I can't put this runtime created Bitmap as content o an ImageView declared into a Fragment?

I am absolutly new in Android development and I am developing my first education app related to a beginner course on Udacity.
The application idea is pretty simple: it is a cousine recipes application in which the use swap from a recepy to another swapping slides right or left in the main activity.
So this is my GitHub repository related to this application: https://github.com/AndreaNobili/PastaFromRome
To swap from a recepy to another I used the fragment, so basically I have an activity_man.xml file that only contains the header and a viewpager for the fragment:
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Then I have the fragment_screen_slide_page.xml that represent a slide related to a single recipe, something like this:
<!-- Dummy content. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="0dp">
<ImageView
android:id="#+id/imageView1"
android:layout_width="fill_parent"
android:scaleType="fitXY"
android:layout_height="250dp" />
<!--
android:src="#drawable/carbonara"/>
android:background="#drawable/carbonara" />
-->
<TextView android:id="#android:id/text1"
style="#style/pastaTitleTextStyle" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0px"
android:layout_weight="1"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
style="#style/HeaderTextStyle"
android:text="Difficoltà:" />
<ImageView
android:id="#+id/difficultyContainer"
android:layout_width="fill_parent"
android:scaleType="fitXY"
android:layout_height="55dp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
This view is a fragmetn that, when is showed, contain the current recipe.
It contains a first ImageView having id imageView1 that show an image related to the current recipe, it works fine.
Then it contains a second ImageView having id difficultyContainer that is an difficulty ranking image created at runtime from the application. Here is where I am going crazy !!!
This is the ScreenSlidePageFragment class (that extends Fragment) that handle the logic of the fragment:
/**
* A fragment representing a single step in a wizard. The fragment shows a dummy title indicating
* the page number, along with some dummy text.
*
*/
public class ScreenSlidePageFragment extends Fragment {
private static final String TAG = "ScreenSlidePageFragment";
/**
* The argument key for the page number this fragment represents.
*/
public static final String ARG_PAGE = "page";
/**
* The fragment's page number, which is set to the argument value for {#link #ARG_PAGE}.
*/
private int mPageNumber;
private static Context context;
/**
* Factory method for this fragment class. Constructs a new fragment for the given page number.
*/
public static ScreenSlidePageFragment create(int pageNumber, Context baseContext) {
ScreenSlidePageFragment fragment = new ScreenSlidePageFragment();
Bundle args = new Bundle();
args.putInt(ARG_PAGE, pageNumber);
fragment.setArguments(args);
context = baseContext;
return fragment;
}
public ScreenSlidePageFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPageNumber = getArguments().getInt(ARG_PAGE);
}
/**
* Method that will be called when the "pasta slider" is slided right or left
* #param inflater
* #param container
* #param savedInstanceState
* #return
*/
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
System.out.println("PAGE NUMBER: "+ mPageNumber);
// Obtain the colosseum_icon.png from the rsources as a Drawable:
//Drawable drawable = getResources().getDrawable(R.drawable.colosseum_icon);
ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.fragment_screen_slide_page, container, false);
ImageView imgSlideView = (ImageView) rootView.findViewById(R.id.imageView1);
/* Retrieve the ImageView having id="difficultyContainer" (where to put the diifficulty
image created):
*/
//ImageView difficultyContainerImageView = (ImageView) rootView.findViewById(R.id.difficultyContainer);
// Load the 2 images for the creation of the "difficulty graphic":
Bitmap chefHatWhite = BitmapFactory.decodeResource(getResources(), R.drawable.chef_hat_white);
Bitmap chefHatOk = BitmapFactory.decodeResource(getResources(), R.drawable.chef_hat_ok);
// Where the previus image will be drawn:
//Canvas canvas = new Canvas();
Canvas difficultyCanvas = creaImgDifficulty();
//switch (mPageNumber + 1) {
switch (mPageNumber) {
case 0:
imgSlideView.setImageResource(R.drawable.carbonara);
((TextView) rootView.findViewById(android.R.id.text1)).setText(getString(R.string.carbonara));
ImageView difficultyContainerImageView1 = (ImageView) rootView.findViewById(R.id.difficultyContainer);
difficultyContainerImageView1.setImageDrawable(new BitmapDrawable(getResources(), ImgUtility.createRankingImg(context, 3)));
break;
case 1:
imgSlideView.setImageResource(R.drawable.amatriciana);
((TextView) rootView.findViewById(android.R.id.text1)).setText(getString(R.string.amatriciana));
break;
case 2:
imgSlideView.setImageResource(R.drawable.gricia_m);
((TextView) rootView.findViewById(android.R.id.text1)).setText(getString(R.string.gricia));
break;
case 3:
imgSlideView.setImageResource(R.drawable.cacio_e_pepe);
((TextView) rootView.findViewById(android.R.id.text1)).setText(getString(R.string.cacio_e_pepe));
break;
case 4:
imgSlideView.setImageResource(R.drawable.ajo_ojo_e_peperoncino);
((TextView) rootView.findViewById(android.R.id.text1)).setText(getString(R.string.ajo_ojo_peperoncino));
break;
}
return rootView;
}
private void createImg(ImageView imgview) {
Canvas canvas;
Bitmap star = BitmapFactory.decodeResource(getResources(), R.drawable.star);
Bitmap output = Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_8888);
canvas = new Canvas(output);
canvas.drawBitmap(star, star.getWidth() + 2, 0, null);
imgview.setImageDrawable(new BitmapDrawable(getResources(), output));
}
private Canvas creaImgDifficulty() {
Canvas canvas;
Bitmap chefHatOk = BitmapFactory.decodeResource(getResources(), R.drawable.chef_hat_ok);
Bitmap output = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
canvas = new Canvas(output);
int space = 10; // the space between images
for(int i = 0; i < 3; i++) {
canvas.drawBitmap(chefHatOk, i * (chefHatOk.getWidth() + space), 0, null);
}
return canvas;
}
/**
* Returns the page number represented by this fragment object.
*/
public int getPageNumber() {
return mPageNumber;
}
}
So basically into the onCreateView() method (that I think is performed when the current fragment is loaded) I have the mPageNumber variable that specify the loaded fragment related to a specific recipe and there is a switch case used to load the specific information of this recipe into this fragment, for example:
case 0: it is the first recipe named carbonara so it put the carbonara.png image (R.drawable.carbonara) into the previous ImageView havving id=imageView1 defined into the fragment_screen_slide_page.xml file.
It works fine.
The problem occur when in the previous code I do:
ImageView difficultyContainerImageView1 = (ImageView) rootView.findViewById(R.id.difficultyContainer);
difficultyContainerImageView1.setImageDrawable(new BitmapDrawable(getResources(), ImgUtility.createRankingImg(context, 3)));
As you can see in the code, the difficultyContainerImageView1 identify the ImageView having id=difficultyContainer in my fragment. Here I set an Image created by the ImgUtility.createRankingImg() method.
public class ImgUtility {
/**
* Method that create the images related to the difficulty of a recepy
* #param context
* #param difficulty that represent the number of chef_hat_ok into the final image
* #return a Bitmap representing the difficult of a recepy
*/
public static Bitmap createRankingImg(Context context, int difficulty) {
// Create a Bitmap image starting from the star.png into the "/res/drawable/" directory:
Bitmap myBitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.chef_hat_ok);
// Create a new image bitmap having width to hold 5 star.png image:
Bitmap tempBitmap = Bitmap.createBitmap(myBitmap.getWidth() * 5, myBitmap.getHeight(), Bitmap.Config.RGB_565);
Canvas tempCanvas = new Canvas(tempBitmap);
// Draw the image bitmap into the cavas:
tempCanvas.drawBitmap(myBitmap, 0, 0, null);
tempCanvas.drawBitmap(myBitmap, myBitmap.getWidth(), 0, null);
tempCanvas.drawBitmap(myBitmap, myBitmap.getWidth() * 2, 0, null);
tempCanvas.drawBitmap(myBitmap, myBitmap.getWidth() * 3, 0, null);
tempCanvas.drawBitmap(myBitmap, myBitmap.getWidth() * 4, 0, null);
return tempBitmap;
}
}
This method should be ok because it seems to me that return a Bitmap but this image is not shown into the fragment ImageView having id=difficultyContainer
Into the logcat I can see the following error log but I don't know if are related to my problem or not:
08-21 19:38:12.315 4239-4925/com.example.android.pastafromrome W/OpenGLRenderer: Bitmap too large to be uploaded into a texture (8730x1836, max=4096x4096)
08-21 19:38:12.335 4239-4925/com.example.android.pastafromrome W/OpenGLRenderer: Bitmap too large to be uploaded into a texture (8730x1836, max=4096x4096)
08-21 19:38:12.335 4239-4925/com.example.android.pastafromrome W/OpenGLRenderer: Bitmap too large to be uploaded into a texture (8730x1836, max=4096x4096)
Why? What I missing? How can I fix this issue? I will very glad to you if you see my GitHub repository and help me to fix it.
The problem is that Android will automaticly resize chef_hat_ok to 1746px width (I guess it depends on device). It seems alright, but you do 5 of them and 5 x 1746px is 8370 and texture can't hold that.
Solution: disable scaling or put resources that depends on density (didn't checked that option).
Disabling scaling.
ImgUtility.java
BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;
Bitmap myBitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.chef_hat_ok, options);
Edit: you will need to set density to canvas tempCanvas.setDensity(myBitmap.getDensity());
Edit2: I would also suggest to make some changes to difficulty container
<ImageView
android:id="#+id/difficultyContainer"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:scaleType="centerInside"
android:adjustViewBounds="true" />

How can I correctly use the Canvas class to show an image into an ImageView in this simple Android app?

I am absolulty new in Android and I am doing some experiment with the Canvas object.
I am trying to add it to a Canvas and then show it into a retrieved ImageView (I know that this is not the standard and simplest way to show an image into an ImageView but this is only a simplified experiment for a further more complex thing that I have to do using Canvas).
So I have a star.png (a 32x32 px icon into my /res/drawable/ folder) and I am trying to
This is my activity_main.xml layout configuration file:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
<ImageView
android:id="#+id/star_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
This layout contain the ImageView having id=star_container that is where I have to draw the image using the Canvas
And this is the MainActivity class that handle this view:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageView imgView = (ImageView) findViewById(R.id.star_container);
Canvas canvas;
Bitmap star = BitmapFactory.decodeResource(getResources(), R.drawable.star);
Bitmap output = Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_8888);
canvas = new Canvas(output);
canvas.drawBitmap(star, star.getWidth() + 2, 0, null);
imgView.setImageDrawable(new BitmapDrawable(getResources(), output));
}
}
So into the onCreate() method I retrieve the ImageView where the image have to be placed. Then I create a Bitmap object retrieving the star.png image from the resoruces that will be added to the otuput Bitmap using the Canvas.
Finally I set this output Bitmap into the retrieve ImageView.
So I expected that, when the app is running, the previous ImageView contains the star.png image but it does not appear.
I have no error when I execute this app but the only output that I obtain is the textual message defined into the TextView.
Why? What is wrong? What am I missing? How can I modify this code and let it work?
According to the documents:
left: The position of the left side of the bitmap being drawn
The problem is here :
canvas.drawBitmap(star, star.getWidth() + 2, 0, null);
You're using a value for left that is out of bitmap bounds, So nothing is drawn, try this: canvas.drawBitmap(star, 0, 0, null);
Android API provides another method to set Bitmap as drawable directly :
ImageView#setImageBitmap(Bitmap bm)
I think it's a better practice to implement a custom View and explore Canvas capabilities there (in onDraw method)
another way - using rect area:
Canvas canvas;
Bitmap star = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
Bitmap output = Bitmap.createBitmap(star.getWidth(), star.getHeight(), Bitmap.Config.ARGB_8888);
canvas = new Canvas(output);
Rect source = new Rect(0, 0, star.getWidth(), star.getHeight());
canvas.drawBitmap(star, null, source, null);
imgView.setImageBitmap(output);

How to slide an ImageView from left to right smoothly in Android?

I need to make an ImageView slide from left to right of the screen with a smooth animation (I want the ImageView to be visible during the transition) I tried with the following code:
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
camion.animate()
.translationX(width)
.setDuration(2000)
.setInterpolator(new LinearInterpolator())
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
//camion.setVisibility(View.GONE);
}
});
The ImageView moves but the animation is laggy and not smooth like I want to.
What am I doing wrong on the code?
Creating this kind of tween animation is simple. Just follow the steps,
Step 1
Create a directory anim inside the res directory and put this as slide.xml
<?xml version="1.0" encoding="utf-8"?>
<set
xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/linear_interpolator"
android:fillAfter="true">
<translate
android:fromXDelta="0%p"
android:toXDelta="75%p"
android:duration="800" />
</set>
You can obviously customize the animation by changing the two attributes fromXDelta and toXDelta. The %p refers to with respect to the parent which simply means that it will move the image 75% with respect to the parent.
Step 2
// Refer the ImageView like this
imageView = (ImageView) findViewById(R.id.img);
// Load the animation like this
animSlide = AnimationUtils.loadAnimation(getApplicationContext(),
R.anim.slide);
// Start the animation like this
imageView.startAnimation(animSlide);
You can also setInterpolator() and setListeners() if you want to. I haven't shown them here to keep it simple. If you need, just let me know.
NOTE
As you have mentioned repeatedly, that you are experiencing a laggy animation. I have tested this animation on 3 real devices and 2 emulators and the animation was buttery smooth on all of them. Tested on low end devices like Moto E to high end devices like Nexus 5 and Galaxy S6.
If you still have a lag running this code, then the test device must be the reason. The code is perfect.
UPDATE
I just checked on my Moto G running on Lollipop too, the animation is running smoothly. This is a very small and light-weight animation, and should never be laggy. If you are still getting a lag, then it must be the device you are testing, or some other piece of code on that Activity making the UI slow or unresponsive.
Try to check which one is applicable to you,
I have tested on a total of 6 devices now with no lag at all. So, you can be rest assured that your production app will not have any lag, it can be your device which is slow
If you are doing some heavy operations like accessing the file system, database, or any other heavy operation, it must be slowing down the UI thread and you are loosing frames. Try to use AsyncTask for these heavy operations
Try this. It will animate the imageview.
ImageView img_animation = (ImageView) findViewById(R.id.img_animation);
Display display = getWindowManager().getDefaultDisplay();
float width = display.getWidth();
TranslateAnimation animation = new TranslateAnimation(0, width - 50, 0, 0); // new TranslateAnimation(xFrom,xTo, yFrom,yTo)
animation.setDuration(1000); // animation duration
animation.setRepeatCount(5); // animation repeat count
animation.setRepeatMode(2); // repeat animation (left to right, right to
// left )
// animation.setFillAfter(true);
img_animation.startAnimation(animation); // start animation
TranslateAnimation animate = new TranslateAnimation(0, -view.getWidth(), 0, 0);
animate.setDuration(500);
animate.setFillAfter(true);
view.startAnimation(animate);
Hope this works for u
animation.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Animation" >
<ImageView
android:id="#+id/img_animation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:layout_marginTop="42dp"
android:src="#drawable/emo_im_laughing" />
</RelativeLayout>
Animation.java
import android.os.Bundle;
import android.app.Activity;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;
public class Animation extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.);
ImageView img_animation = (ImageView) findViewById(R.id.img_animation);
TranslateAnimation animation = new TranslateAnimation(0.0f, 400.0f,
0.0f, 0.0f);
animation.setDuration(5000);
animation.setRepeatCount(5);
animation.setRepeatMode(2);
animation.setFillAfter(true);
img_animation.startAnimation(animation);
}
}
try the code below
TranslateAnimation animation = new TranslateAnimation(0.0f, 0.0f, 0.0f, 1500.0f); // new TranslateAnimation (float fromXDelta,float toXDelta, float fromYDelta, float toYDelta)
animation.setDuration(2000); // animation duration
animation.setRepeatCount(1); // animation repeat count if u repeat only once set to 1 if u don't repeat set to 0
animation.setFillAfter(false);
your_view .startAnimation(animation);//your_view for mine is imageView
public class MainActivity extends Activity {
int windowwidth;
int windowheight;
private LayoutParams layoutParams;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
windowwidth = getWindowManager().getDefaultDisplay().getWidth();
windowheight = getWindowManager().getDefaultDisplay().getHeight();
final ImageView img = (ImageView) findViewById(R.id.imageView1);
img.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
LayoutParams layoutParams = (LayoutParams) img
.getLayoutParams();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
int x_cord = (int) event.getRawX();
int y_cord = (int) event.getRawY();
if (x_cord > windowwidth) {
x_cord = windowwidth;
}
if (y_cord > windowheight) {
y_cord = windowheight;
}
layoutParams.leftMargin = x_cord - 25;
layoutParams.topMargin = y_cord - 75;
img.setLayoutParams(layoutParams);
break;
default:
break;
}
return true;
}
});
}
}
To Move imageview
from Right to Left Using #Aritra Roy Answer.
Use this code
<?xml version="1.0" encoding="utf-8"?>
<set
xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/linear_interpolator"
android:fillAfter="true">
<translate
android:fromXDelta="75%p"
android:toXDelta="0%p"
android:duration="100000" />
</set>
Now we have MotionLayout try to use that for very clean and smooth sliding animation.

How to add a Marker/Pin on an ImageView Android?

I would like to ask on how to implement or add a marker on an imageView.
I rendered an SVG using svglib and used a customImageView so that I can zoom and pan around the image.
here is my code on how i used my customImageView
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
SVG svg;
switch (mNum) {
case 1:
svg = SVGParser.getSVGFromResource(getResources(), R.raw.t1);
break;
case 2:
svg = SVGParser.getSVGFromResource(getResources(), R.raw.t2);
break;
case 3:
svg = SVGParser.getSVGFromResource(getResources(), R.raw.t3);
break;
case 4:
svg = SVGParser.getSVGFromResource(getResources(), R.raw.t4);
break;
default:
svg = SVGParser.getSVGFromResource(getResources(),
R.raw.android);
}
View v = inflater.inflate(R.layout.hello_world, container, false);
View tv = v.findViewById(R.id.text);
imageView = (GestureImageView) v.findViewById(R.id.imageView1);
imageView.setStrict(false);
imageView.setStartingScale(lastScale);
// if(lastXPosition!=0 && lastYPosition!=0)
imageView.setStartingPosition(lastXPosition, lastYPosition);
// Log.i("tag",
// "lastXPosition" + lastXPosition);
// Log.i("tag",
// "lastYPosition" + lastYPosition);
// Log.i("tag",
// "lastScale" + lastScale);
// imageView.setRotation(45);
// imageView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
if (Build.VERSION.SDK_INT > 15)
imageView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
imageView.setImageDrawable(svg.createPictureDrawable());
((TextView) tv).setText("Floor number: " + mNum);
imageView.setBackgroundColor(Color.WHITE);
// tv.setBackgroundDrawable(getResources().getDrawable(
// android.R.drawable.gallery_thumb));
// imageView.setScaleType(ScaleType.CENTER);
// ((GestureImageView)imageView).setScale(x);
return v;
}
Now I would like to add a pin just like the image below...
(source: modality.com)
But my problem is that when I pan around the marker I added is not bonded with the image SVG thus left behind at a certain position when panning...
Here's my code...
NOTE: Not yet final... I'm still looking for a way to get this working and I am using a zoomed in imageview as a map...
#Override
protected void onDraw(Canvas canvas) {
if (layout) {
if (drawable != null && !isRecycled()) {
canvas.save();
float adjustedScale = scale * scaleAdjust;
canvas.translate(x, y);
if (rotation != 0.0f) {
canvas.rotate(rotation);
}
if (adjustedScale != 1.0f) {
canvas.scale(adjustedScale, adjustedScale);
}
drawable.draw(canvas);
canvas.restore();
}
if (drawLock.availablePermits() <= 0) {
drawLock.release();
}
}
// ---add the marker---
Bitmap marker = BitmapFactory.decodeResource(getResources(),
R.drawable.search_marker_icon);
canvas.drawBitmap(marker, 40, 40, null);
Paint mPaint = new Paint();
mPaint.setColor(Color.RED);
canvas.drawCircle(60, 60, 5, mPaint);
super.onDraw(canvas);
}
Thanks.... I'm new to android :) hope you can help me....
This is a nice library for displaying images, which supports zooming/panning and adding pins over the image
https://github.com/davemorrissey/subsampling-scale-image-view
drawable.draw(canvas);
// ---add the marker---
Bitmap marker = BitmapFactory.decodeResource(getResources(),
R.drawable.search_marker_icon);
canvas.drawBitmap(marker, 40, 40, null);
Paint mPaint = new Paint();
mPaint.setColor(Color.RED);
canvas.drawCircle(60, 60, 5, mPaint);
canvas.restore();
}
if (drawLock.availablePermits() <= 0) {
drawLock.release();
}
}
super.onDraw(canvas);
}
You need to do this before canvas.restore..... :D got this solution last year...... thnx for the help guys.... my app is almost done :)
An implementation of an HTML map like element in an Android View:
Supports images as drawable or bitmap in layout
Allows for a list of area tags in xml
Enables use of cut and paste HTML area tags to a resource xml (ie, the ability to take an HTML map - and image and use it with minimal editing)
Supports panning if the image is larger than the device screen
Supports pinch-zoom
Supports callbacks when an area is tapped.
Supports showing annotations as bubble text and provide callback if the bubble is tapped
try this link you will find your solution https://github.com/catchthecows/AndroidImageMap

Categories

Resources