In my app I have an imageview on screen "A" and a webview on screen "B".
On screen "A" I start an sync task in order to download and show a png file into the imageview.
On screen "B" I load some HTML info. in which the link to the same png on screen "A" is included.
The problem is that the same image looks different on both screens. When loaded in the imageview, the png looks way smaller than when it is loaded in the webview.
The height and the width of the imageview are set to wrap_content. There is no additional scaling or something similar.
Why is this happening?
---EDIT---
screen "A" layout
<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/background_repeat">
<ImageView
android:id="#+id/logo_image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_gravity="center_horizontal"/>
</RelativeLayout>
screen "B" layout
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<WebView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/about_us_web_view"
/>
</RelativeLayout>
screen "A" asyncTask
private class DownloadLogoTask extends AsyncTask<ImageView, String, Bitmap> {
private String urlString;
public DownloadLogoTask(String urlString) {
this.urlString = urlString;
}
#Override
protected Bitmap doInBackground(ImageView... imageViews) {
try {
URL url = new URL(urlString);
HttpURLConnection urlConnection = (HttpURLConnection)url.openConnection();
InputStream is = urlConnection.getInputStream();
Bitmap bitmap = BitmapFactory.decodeStream(is);
if(bitmap != null) {
return bitmap;
}
} catch (Exception e) {
}
return null;
}
#Override
protected void onPostExecute(Bitmap result) {
if(result != null) {
logoImageView.setImageBitmap(result);
}
}
}
screen "B" usage of the webView
aboutUsWebView.loadData(descriptionStr, "text/html", "UTF-8");
Related
I have a ListView with a custom adapter. Every row has a Pokémon sprite that I download to a bitmap, the sprites are always 96 x 96. I manually downloaded a dummy image and put it in my drawables folder, and it renders fine:
How it should be
But when I actually download the images programmatically, it gives me this result:
How it is
Why are then suddenly so small? When I sysout the height and width of the downloaded bitmaps, it says 96 x 96, but it clearly doesn't render as 96 x 96.
Here's the code of the task that downloads the image
private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
#Override
protected Bitmap doInBackground(String... urls) {
String urldisplay = urls[0];
Bitmap bm = null;
try {
InputStream in = new java.net.URL(urldisplay).openStream();
bm = BitmapFactory.decodeStream(in);
} catch (Exception e) {
e.printStackTrace();
}
return bm;
}
}
How I call the task
try {
Bitmap bm = new DownloadImageTask().execute(dataModel.getSpriteUrl()).get();
viewHolder.sprite.setImageBitmap(bm);
} catch (Exception e) {
e.printStackTrace();
}
Pokemon row XML
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="#+id/img_sprite"
android:layout_width="96dp"
android:layout_height="96dp"
android:scaleType="fitCenter" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="left|center_vertical"
android:orientation="vertical">
<TextView
android:id="#+id/text_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#android:color/black"
android:textSize="20sp"
android:textStyle="bold" />
<TextView
android:id="#+id/text_cp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18sp" />
<TextView
android:id="#+id/text_gendershiny"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="end"
android:orientation="vertical">
<Button
android:id="#+id/btn_delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:backgroundTint="#color/colorPrimary"
android:text="DELETE"
android:textColor="#ffffff"
android:textSize="16sp"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
You might want to take a look at this website. I gives some helpful tips of how to use the scaleType attribute with the ImageView:
https://robots.thoughtbot.com/android-imageview-scaletype-a-visual-guide
Please see the edit at the bottom of this answer.
Now to the issue with using get() method of an AsyncTask
Use an interface to let you know when the AsyncTask is complete:
public interface BitmapLoaderListener {
void onCompletedBitmapLoaded(Bitmap bm);
}
Your AsyncTask could look like this:
public class BitmapLoader extends AsyncTask<String, Integer, Bitmap> {
private static final String TAG = BitmapLoader.class.getSimpleName();
private BitmapLoaderListener mListener;
private String imageUrl = "";
public BitmapLoader(String imageUrl, BitmapLoaderListener listener){
this.imageUrl = imageUrl;
this.mListener = listener;
this.selectedSource = source;
}
#Override
protected Bitmap doInBackground(String... params) {
Bitmap bm = null;
try{
// Your code here !!!
}
catch (Exception ex){
Log.e(TAG, ex.getMessage());
}
return bm;
}
protected void onPostExecute(Bitmap bm) {
mListener.onCompletedBitmapLoaded(bm);
}
}
Call the AsyncTask from your RecyclerView from the onBindViewHolder:
#Override
public void onBindViewHolder(final MyViewHolder holder, final int position){
MyData data = mData.get(position);
// Add whatever code you need here
BitmapLoaderListener listener = new BitmapLoaderListener() {
#Override
public void onCompletedBitmapLoaded(Bitmap bm) {
if (bm == null) return;
holder.myImageView.setImageBitmap(bm);
}
};
BitmapLoader loader = new BitmapLoader(imageUrl, listener);
loader.execute();
}
You could implement a cache type system where you persist the images to the device storage and load them from the internet only when needed. I do this with a lot of my apps. This is possible, but it requires experience with dealing with threads and resources... As Angelina pointed out you can always use Glide or Picasso libraries. Although I very rarely use third party libraries in this case you might want to consider it--they are well designed and well maintained libraries.
Edit:
Using a scaling method createScaledBitmap()for every downloaded image seems a bit heavy weight.
You might want to make this simple change to your layout file:
<ImageView
android:id="#+id/img_sprite"
android:layout_width="96dp"
android:layout_height="96dp"
android:scaleType="fitCenter"/>
There are many ways to achieve the result you want by making some changes to your layout file. I just pick the easiest with regard to the image size you are downloading (96x96).
This example takes the image and forces it into an ImageView 96dpx96dp so that the image is centered and scaled to fit the view bounds maintaining the original aspect ratio.
This is much easier to maintain and modify as well as much more light weight then using createScaledBitmap() method for every image--rather it needs it or not, ouch!
Using AsyncTask to download an image is not the common thing. Usually this is done with a library called Glide. It downloads the image in background thread and caches it. You can also set ScaleType of the image there.
Loading an image that is larger than the width of a Galaxy Tab 2 P5100 (running 4.1.2) into an ImageView adds some sort of top/bottom padding to the loaded image.
Here's a screenshot with Show layout boundaries turned on:
Here's how it should look (from a Nexus 10 running 4.4.2):
The code I use (for both examples above) is
public class ImageBugActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bug);
// This bug is still reproducible if I use the
// Universal-Image-Loader library or if I change the dimensions of
// the image to a different width
loadImage("http://placehold.it/1600x1000", (ImageView)findViewById(R.id.image));
}
private void loadImage(final String url, final ImageView view) {
new Thread(new Runnable() {
#Override
public void run() {
try {
final Bitmap bitmap = BitmapFactory.decodeStream(new URL(url).openConnection().getInputStream());
runOnUiThread(new Runnable() {
#Override
public void run() {
view.setImageBitmap(bitmap);
}
});
} catch (Exception e) {
Log.e("loadImage", e.getMessage(), e);
}
}
}).start();
}
}
And the layout file is
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="On a Galaxy Tab 2 the image below it is pushed to the center of the remaining space." />
<ImageView
android:id="#+id/image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top" />
</LinearLayout>
Does this seem to be an Android/Samsung bug or am I making a dumb mistake?
Setting the android:scaleType of the ImageView to "fitStart" should do the trick.
You should use "match_parent" for layout_height of the ImageView.
<ImageView
android:id="#+id/image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="top" />
I have the problem that I have a layout with an ImageView. With AsyncTask I load an image from the web. It is a panorama picture. If I start up the Fragment, the image I load with src="#drawable/pano" is shown perfectly. It has full height and I can scroll through the panorama.
As soon as the new image is loaded into the ImageView the imageview rescales so that the height is:
Before the AsyncTask (Image is loaded from drawables...):
And this is after the AsyncTask loaded the image:
Here is my xml file:
<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"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:overScrollMode="never"
android:scrollbars="none" >
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="match_parent" >
<ImageView
android:id="#+id/img1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentTop="true"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:src="#drawable/pano" />
</RelativeLayout>
</HorizontalScrollView>
AsyncTask Code:
public class DownloadPanorama extends
AsyncTask<ImageView, Void, Bitmap> {
ImageView imageView;
Bitmap bm;
public DownloadPanorama(ImageView mChart) {
imageView = mChart;
}
#Override
protected Bitmap doInBackground(ImageView... imageViews) {
return download_Image((String) imageView.getTag());
}
#Override
protected void onPostExecute(Bitmap result) {
imageView.setImageBitmap(result);
}
private Bitmap download_Image(String url) {
Bitmap bm = null;
try {
URL aURL = new URL(url);
URLConnection conn = aURL.openConnection();
conn.connect();
InputStream is = conn.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
bm = BitmapFactory.decodeStream(bis);
bis.close();
is.close();
return bm;
}
}
Also happens when not using AsyncTask and only using raw setImageBitmap... So I don't know if I have to change the scaleType in my xml file or if I need to set it again after loading a new image?
I would try changing:
android:layout_height="wrap_content"
to
android:layout_height="fill_parent"
in your ImageView.
If that doesn't work, you might be able to scale your bitmap:
myBitmap = Bitmap.createScaledBitmap(myBitmap, width, height,true);
EDIT
It sounds like from your comments and updated question that you know the size you would like the image to be (1200x400). You have two things you can do to get this size. The first, and recommended, is to replace the line
bm = BitmapFactory.decodeStream(bis);
with
BitmapFactory.Options options = new BitmapFactory.Options();
options.outWidth=1200;
options.outHeight=400;
bm = BitmapFactory.decodeStream(bis, new Rect(0,0,0,0), options);
The other option is to change your View bounds. In your comments above, it sounds like the bounds might change, so you would have to repeat this each time you loaded a new image of different size:
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) imageView.getLayoutParams();
params.width = 1200;
params.height = 400;
imageView.setLayoutParams(params);
You need to change
android:adjustViewBounds="true"
to
android:adjustViewBounds="false"
So I am loading images from URLs with this method
public Drawable loadImage(String url) {
try {
InputStream is = (InputStream) new URL(url).getContent();
Drawable d = Drawable.createFromStream(is, "src name");
return d;
} catch (Exception e) {
System.out.println(e.getMessage()+" oh noo ");
return null;
}
}
But I want the image's width to be the same as its parent (that is the root element with height and width 100%). I couldn't find a way to do it using only XML. It always leaves paddings on the edges. And I found out it is because the image doesn't have the same ratio of the screen. screen is, for example 16:9 and image is 4:3. Android will make paddings to fill this difference.
Do you know how can I do it programmatically when I load the image? And I need this image to remain as big as the screen's width even when the device rotates (so I think I will need to calculate it gain)
I am using this code to get the size of the screen
public Size getScreenSize(){
Size screenSize = new Size();
DisplayMetrics metrics = new DisplayMetrics();
this.activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
screenSize.height = metrics.heightPixels;
screenSize.width = metrics.widthPixels;
return screenSize;
}
public class Size{
public double height;
public double width;
}
#EDIT1
This is how I insert the drawable in the View. The view is already declared in the activity's XML
ImageView picture = (ImageView) findViewById(R.id.picture);
picture.setImageDrawable(loadImage(url));
#EDIT2
this is how I wrote the activity layout and its style
<LinearLayout 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"
android:orientation="vertical"
tools:context=".MainActivity" >
<!-- style="#style/globalHeader" -->
<LinearLayout
style="#style/globalHeader"
>
<TextView
android:id="#+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#fff"
android:textSize="18sp"
android:textStyle="bold"
/>
<TextView
android:id="#+id/subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#fff"
android:textSize="14sp"
/>
</LinearLayout>
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/picture"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
android:background="#f00"
>
</ImageView>
<TextView
android:id="#+id/desc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="20dp"
/>
<TextView
android:id="#+id/details"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</LinearLayout>
This is the appearance I want to achieve
https://docs.google.com/a/uniriotec.br/file/d/0B2abPynX9PhkODhRVEkwcUphY28/edit?pli=1
I think so this is the one you are finding for.
just rescale the image of drawable taken from internet.
Bitmap bit = BitmapFactory.decodeResource(getApplicationContext()
.getResources(), drawable);
if (bit != null) {
Bitmap resizedBitmap = Bitmap.createScaledBitmap(bit, width,
height, true);
imageView.setBitmap(resizedBitmap);
}
the width and height are calculated below
DisplayMetrics disp = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(disp);
int width = disp.widthPixels;
int height = disp.heightPixels;
#EDIT
private Bitmap loadImage(String URL)
{
Bitmap bitmap = null;
InputStream in = null;
try {
in = OpenHttpConnection(URL);
bitmap = BitmapFactory.decodeStream(in);
in.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
return bitmap;
}
private InputStream OpenHttpConnection(String urlString)
throws IOException
{
InputStream in = null;
int response = -1;
URL url = new URL(urlString);
URLConnection conn = url.openConnection();
if (!(conn instanceof HttpURLConnection))
throw new IOException("Not an HTTP connection");
try{
HttpURLConnection httpConn = (HttpURLConnection) conn;
httpConn.setAllowUserInteraction(false);
httpConn.setInstanceFollowRedirects(true);
httpConn.setRequestMethod("GET");
httpConn.connect();
response = httpConn.getResponseCode();
if (response == HttpURLConnection.HTTP_OK)
{
in = httpConn.getInputStream();
}
}
catch (Exception ex)
{
throw new IOException("Error connecting");
}
return in;
}
Directly take the bitmap image and rescale it and use it.
Not sure how will it behave with device rotation, but I believe you actually can do it from your xml layout, setting your ImageView.ScaleType to CENTER_CROP should do the trick.-
CENTER_CROP : Scale the image uniformly (maintain the image's aspect ratio) so that both dimensions (width and height) of the image will be equal to or larger than the corresponding dimension of the view (minus padding).
<ImageView
android:id="#+id/picture"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop" />
Try this
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:id="#+id/picture"
android:scaleType="fitXY"
android:background="#f00"
>
I am developing an app in which user will take Picture from camera and display it on preview screen having image view.
**CameraCapture.java**
class ButtonClickHandler implements View.OnClickListener
{
public void onClick( View view ){
myVib.vibrate(50);
startCameraActivity();
}
}
protected void startCameraActivity()
{
File filenew = new File( _path );
Uri outputFileUri = Uri.fromFile( filenew );
Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE );
intent.putExtra( MediaStore.EXTRA_OUTPUT, outputFileUri );
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
startActivityForResult( intent, 0 );
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
switch( resultCode )
{
case 0:
break;
case -1:
//pictaken++;
onPhotoTaken();
break;
}
}
protected void onPhotoTaken()
{
//pictaken=true;
Intent i = new Intent(CameraCapture.this,Preview.class);
startActivity(i);
}
In my Preview class the captured picture is displayed on ImageView
**Preview.java**
File imgFile = new File("/sdcard/DCIM/Camera/test.jpg");
if(imgFile.exists()){
// Bitmap myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
ImageView myImage = (ImageView) findViewById(R.id.image);
Bitmap myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
Matrix mat = new Matrix();
String degree="90";
mat.postRotate(Integer.parseInt(degree));
Bitmap bMapRotate = Bitmap.createBitmap(myBitmap, 0, 0,myBitmap.getWidth(),myBitmap.getHeight(), mat, true);
myImage.setImageBitmap(bMapRotate);
//myImage.setImageBitmap(myBitmap);
}
_image = ( ImageView ) findViewById( R.id.image );
Is there is any way to show progress bar on the ImageView till it load the Captured image from SD card.
Thnx in advance :)
Put your ImageView and Progressbar in a RelativeLayout. For your ProgressBar, use:
android:layout_centerInParent="true"
Which will center it in the RelativeLayout, meaning over the ImageView. You might also want to hide the ProgressBar when the image has loaded:
progressBar.setVisibility(View.Gone)
when the image has been loaded.
Sample code:
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true"/>
<ProgressBar
style="?android:attr/progressBarStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:visibility="visible"/>
</RelativeLayout>
This is my solution. It is a little bit different. You can use it to create intro view with an image and progress bar. Here, progress bar is at 150dp to the bottom of center. FrameLayout can also be used.
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<ImageView
android:id="#+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="#string/intro_description"
android:scaleType="fitXY"
android:src="#drawable/intro" />
<ProgressBar
android:id="#+id/progress"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="150dp"
android:visibility="visible" />
</FrameLayout>