I'm adding images to a gridview, everything works perfectly until I turn the phone sideways, all the images in the GridView disapper and this error appears on the log
SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length
The images I'm using for my GridView are taken with the phone camera like this
Intent camera_intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(camera_intent, CAMERA_PIC_REQUEST);
After that I call the image Adapter
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch(requestCode){
case 0:
if(resultCode==RESULT_OK){
Bitmap thumbnail = (Bitmap) data.getExtras().get("data");
Bitmap.createScaledBitmap(thumbnail, 100, 100, true);
Drawable drawable = new BitmapDrawable(getResources(), thumbnail);
list.add(drawable);
GridView gv = (GridView)findViewById(R.id.GridV1);
gv.setAdapter(new ImageAdapter(this, list));
}
}
}
And finally this is where I add my images in the ImageAdapter
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
if (convertView == null) {
imageView = new ImageView(mContext);
imageView.setLayoutParams(new GridView.LayoutParams(130, 130));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setPadding(10, 10, 10, 10);
} else {
imageView = (ImageView) convertView;
}
imageView.setImageDrawable(mThumbIds.get(position));
return imageView;
}
I think it has something to do with the scale, but I'm not sure, can't find a solution to this problem.
Like Sochimickox said, your layout gets redrawn when you turn it. So there is two way that i see, first is disabling the redrawn. Since we know your error's cause is "spans", one of these should help you:
First one
Or this one
Probably the first would do it, but i recommend designing the app for both landscape and portait modes. To do that, you should crete one more folder in your resource named layout-port. Than you can simply copy the xml file here, select the portait look from top bar at "Graphical Layout" bar. I say read here first. It's from Android Developer site, just incase, I'm putting another tutorial link too.
Just to be clear, layout-port is for portait mode. If you want to design for lanscape, use layout-land. You can design for different screen size with this way too. Like layout-sw600dp
The images dissapear because when the configuration changes, the layout gets redrawn.
You can set landscape mode by default on your app by adding this to OnCreate:
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
Or set it to portrait mode:
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
EDIT
Try this:
#Override
public void onConfigurationChanged(Configuration newConfig) {
newConfig.orientation = getResources().getConfiguration().orientation;
super.onConfigurationChanged(newConfig);
}
Related
I'm using the loadermanager for my app. On Orientation change my app can reload the TextView, but the imagestream for my drawable is not loaded the second time. On the first load the picture shows ,but after an orientation change it stays in its unchanged state. (in my case , a white square)
#Override
public void onLoadFinished(Loader<Person> loader, Person p) {
tvProfileName.setText(p.getName());
Log.i("img stream", ""+p.getImageStream());
Bitmap b = BitmapFactory.decodeStream(p.getImageStream());
Drawable d = new BitmapDrawable(getResources(), b);
ivMenuPhoto.setImageDrawable(d);
}
The setText is working and my name is loaded, even after the orientation change. But the setimagedrawable is not working. The p.getImageStream is not null...
Is my drawable maybe set before the layout is finished changing? I'm just very confused, because my TextView is working.
edited for my solution:
I added a Drawable attribute in the Person Object. So the loader can also hold that part. Then I created the getters and setters. And then I added the onResume to also set my drawable after the orientation change
#Override
public void onLoadFinished(Loader<Person> loader, Person p) {
tvProfileName.setText(p.getName());
Drawable d = new BitmapDrawable(getResources(), p.getPersonphoto());
this.personPhoto = d;
ivMenuPhoto.setImageDrawable(d);
}
#Override
protected void onResume() {
super.onResume();
ivMenuPhoto.setImageDrawable(this.personPhoto);
}
I have a GridView with 4 columns and n-rows. Each cell is simply an ImageView. My custom adapter's getView() code looks like this:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
if (convertView == null) { // if it's not recycled, initialize some attributes
imageView = new ImageView(mContext);
} else {
imageView = (ImageView) convertView;
}
imageView.setLayoutParams(new GridView.LayoutParams(100, 100));
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
imageView.setPadding(1, 1, 1, 1);
//imageView.setAdjustViewBounds(true);
if(imageLoader != null) {
String url = randomImage();
imageView.setContentDescription(url);
imageLoader.DisplayImage(url, imageView);
}
return imageView;
}
The imageLoader will pick a random URL and in the background, go fetch it and update the ImageView accordingly. That works fine and dandy. The problem is that the resulting images seem to be using a scale type of FIT_START instead of FIT_XY. I'm explicitly setting this to FIT_XY and even set it again inside of the code that sets the imageView's drawable... still its not FIT_XY and i'm stumped. Ideas?
Edited to remove the call to setAdjustViewBounds().
So I just found the issue. I was using Romain Guy's code for creating a RoundedDrawable from a bitmap -- to get rounded corners, ala iOS, as shown here: curious-creature.org/2012/12/11/… ... when i skip the RoundedDrawable conversion, it works fine. Something in the RoundedDrawable code is what is throwing this whole thing off. I'll just need to find another method to round the corners of the imageview. I am using CENTER_CROP now thanks to #kcoppock ! :)
I followed another StackOverflow tutorial where you can capture a bitmap from the camera and set it to your image view. The issue I am having is that the picture that is returned is very small and does not fill the rest of the screen. In my XML I do the following...
<ImageView
android:id="#+id/imgview"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
If I change to "fill_parent" I get a larger image, but my question now is how would I go about getting the actual size image and putting it on a scrollable (in both the x and y directions) view container.
Thanks!
BTW, here is the code for capturing the Bitmap from the camera...
public class MainActivity extends Activity implements OnClickListener
{
private ImageView imageView;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d("matt","1");
Button b = (Button)this.findViewById(R.id.btn);
imageView = (ImageView)this.findViewById(R.id.imgview);
b.setOnClickListener(this);
}
#Override
public boolean onCreateOptionsMenu(Menu menu)
{
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
#Override
public void onClick(View v)
{
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(cameraIntent,1888);
}
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
if(requestCode == 1888)
{
Log.d("matt", "3.a");
Bitmap photo = (Bitmap) data.getExtras().get("data");
Log.d("matt", "3.b");
imageView.setImageBitmap(photo);
Log.d("matt", "3.c");
}
}
If you need the dimensions of the image being captured then you can use:
int height = photo.getHeight();
int width = photo.getWidth();
Otherwise, if you would like to find out the size of the image captured (in megabytes) then please refer to my answer to this question: https://stackoverflow.com/a/11846455/1512836
[EDIT] - Please check this for scrolling an image view: Images in ScrollView in android
The caller may pass an extra EXTRA_OUTPUT to control where this image will be written. If the EXTRA_OUTPUT is not present, then a small sized image is returned as a Bitmap object in the extra field. This is useful for applications that only need a small image. If the EXTRA_OUTPUT is present, then the full-sized image will be written to the Uri value of EXTRA_OUTPUT.
I am working on an android application. I have an activity, say A, which fills the entire screen with views..On a button click in A I want to start another activity, say B, which also has some views and controls. I want activity B to be offscreen , and want to take the screenshot of B from A . Is it possible?
Note: I am successful in taking the screenshot of page A by saving the drawing cache in to a bitmap, but struggling to take the offscreen page's screenshot.
Yes it is possible...You should extend ActivityGroup in Activity 'A'.
Then do this in your button click event...
View view =getLocalActivityManager().startActivity("B",new Intent(this,B.class).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)).getDecorView();
then convert that view as bitmap...
I think this is helpful for you...
Well I have achieved what I want. These are the steps I used.
Start activity B with startActivityForResult() instead of
startActivity().
Intent bIntent = new Intent(A.this,B.class);
startActivityForResult(bIntent,B_REQUEST_CODE);
In onCreate of activity B take mainLayout of B and enable its
drawing cache
final LinearLayout layout = (LinearLayout)
findViewById(R.id.app_parent_layout);
layout.setDrawingCacheEnabled(true);
layout.setDrawingCacheQuality(LinearLayout.DRAWING_CACHE_QUALITY_HIGH);
In activity B wait till its layout is drawn completely(This is very
important). For that in onCreate() of activity B, get mainLayout of
B, use ViewTreeObserver to get a call back when its layout is drawn
completely.
ViewTreeObserver vto = layout.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
layout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
getDrawingBitmap();
}
});
Now getDrawingBitmap() gets called when layout is drawn completely.
There take your screenshot.
public void getDrawingBitmap(){
LinearLayout mainLayout = (LinearLayout)
findViewById(R.id.app_parent_layout);
Bitmap b = mainLayout.getDrawingCache();
File file = saveBitmapAsFile(b);
Intent resultIntent = new Intent();
resultIntent.putExtra("FullFileName",file.getAbsolutePath());
setResult(Activity.RESULT_OK,resultIntent);
finish();
}
Here I am taking bitmap and saving it as a file and returning the
filename as a result code. I am sure there are better method to send
the bitmap to parent activity than saving as a file and sending
filename. But I have a requirement anyway to save bitmap for
sometime. So For me this is the easier method. After setting result
finish activity.
Now on Activity A onActivityResult() retrieve the filename.
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == B_REQUEST_CODE){
if (resultCode == Activity.RESULT_OK) {
String newText = data.getStringExtra("FullFileName");
File dir = new File (newText);
}
}
}
I think it would be very hard to do so, as I know no way to get in control of the drawing methods of those views, and the android OS won't draw them either unless visible.
However it may be possible to foreground the other View for only a short time to fill its drawing cache. Maybe it can be put background again before it even becomes visible, as for smooth experience the OS seems to draw views offscreen before they are actually composed to foreground.
Another trick could be to attach your foreground View as an child View onto the background, and give it a very slight alpha transparency. The WebView for example can be superimposed this way very well, actually forcing both the WebView and its background to be drawn. Maybe this works with other Views too.
i m using this way its working great but there is an issue i m just taking snapshots of one layout first time when i take the snapshoot it gives me right pic but after some changes i take it again it gives me previous snapshoot.
RelativeLayout layout = (RelativeLayout)findViewById(R.id.mainview);
layout.setDrawingCacheEnabled(true);
layout.setDrawingCacheQuality(LinearLayout.DRAWING_CACHE_QUALITY_HIGH);
layout.buildDrawingCache();
Bitmap bitmap = layout.getDrawingCache();
File file = new File(Environment.getExternalStorageDirectory().toString() + "/sPenimg.png");
FileOutputStream ostream;
try {
ostream = new FileOutputStream(file);
bitmap.compress(CompressFormat.PNG, 100, ostream);
ostream.flush();
ostream.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
This issue is solved to add
((RelativeLayout)findViewById(R.id.mainview)).destroyDrawingCache();
I'm working with a ListView, trying to get the convertView / referenceHolder optimisation to work properly but it's giving me trouble. (This is the system where you store the R.id.xxx pointers in as a tag for each View to avoid having to call findViewById). I have a ListView populated with simple rows of an ImageView and some text, but the ImageView can be formatted either for portrait-sized images (tall and narrow) or landscape-sized images (short and wide). It's adjusting this formatting for each row which isn't working as I had hoped.
The basic system is that to begin with, it inflates the layout for each row and sets the ImageView's settings based on the data, and includes an int denoting the orientation in the tag containing the R.id.xxx values. Then when it starts reusing convertViews, it checks this saved orientation against the orientation of the new row. The theory then is that if the orientation is the same, then the ImageView should already be set up correctly. If it isn't, then it sets the parameters for the ImageView as appropriate and updates the tag.
However, I found that it was somehow getting confused; sometimes the tag would get out of sync with the orientation of the ImageView. For example, the tag would still say portrait, but the actual ImageView would still be in landscape layout. I couldn't find a pattern to how or when this happened; it wasn't consistent by orientation, position in the list or speed of scrolling. I can solve the problem by simply removing the check about convertView's orientation and simply always set the ImageView's parameters, but that seems to defeat the purpose of this optimisation.
Can anyone see what I've done wrong in the code below?
static LinearLayout.LayoutParams layoutParams;
(...)
public View getView(int position, View convertView, ViewGroup parent){
ReferenceHolder holder;
if (convertView == null){
convertView = inflater.inflate(R.layout.pick_image_row, null);
holder = new ReferenceHolder();
holder.getIdsAndSetTag(convertView, position);
if (data[position][ORIENTATION] == LANDSCAPE) {
// Layout defaults to portrait settings, so ImageView size needs adjusting.
// layoutParams is modified here, with specific values for width, height, margins etc
holder.image.setLayoutParams(layoutParams);
}
holder.orientation = data[position][ORIENTATION];
} else {
holder = (ReferenceHolder) convertView.getTag();
if (holder.orientation != data[position][ORIENTATION]){ //This is the key if statement for my question
switch (image[position][ORIENTATION]) {
case PORTRAIT:
// layoutParams is reset to the Portrait settings
holder.orientation = data[position][ORIENTATION];
break;
case LANDSCAPE:
// layoutParams is reset to the Landscape settings
holder.orientation = data[position][ORIENTATION];
break;
}
holder.image.setLayoutParams(layoutParams);
}
}
// and the row's image and text is set here, using holder.image.xxx
// and holder.text.xxx
return convertView;
}
static class ReferenceHolder {
ImageView image;
TextView text;
int orientation;
void getIdsAndSetTag(View v, int position){
image = (ImageView) v.findViewById(R.id.pickImageImage);
text = (TextView) v.findViewById(R.id.pickImageText);
orientation = data[position][ORIENTATION];
v.setTag(this);
}
}
Thanks!
Rather than putting orientation as a data member of ReferenceHolder, examine the actual LayoutParams of the ImageView to see what orientation it is in. This way, by definition, you can't get out of sync somehow.
To be honest, I'm confused by the code you have there, as you never seem to change layoutParams, which would seem to be kinda important. Or, shouldn't you have layoutParamsPortrait and layoutParamsLandscape or something? To me, it looks like the rules are:
If it's portrait and the row is initially created, leave it portrait
Everything else is landscape, regardless of what the orientation flag says, since you always set it to layoutParams, which is presumably landscape