Gallery with setScaleX/Y on children - android

I have a gallery feeded by custom adapter using custom views as elements. I need these elements to be scaled by 70% by default. The problem is that gallery behaves like they are at 100% size with 30% transparent padding = spacing between elements are just big. For better understanding I attached two images with elements scaled to 100% and 70%.
Elements scaled to 100%
Elements scaled to 70%
I cannot hardcode the setSpacing as this would behave weird on different resolutions. I tried setSpacing(0) with no luck. How can I achieve that gallery would behave like the elements are small (70%) and not the original size?
I'm scaling the elements by adding setScaleX/Y to the constructor of custom element MagazineCell which extends RelativeLayout:
public MagazineCell(Context context) {
super(context);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
layout = (RelativeLayout) inflater.inflate(R.layout.mag_big, null);
addView(layout);
this.setScaleX(0.7f);
this.setScaleY(0.7f);
}
I also tried to set the scale in drawChild() of the gallery with no luck. In adapter I'm simply using this class for gallery elements:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
MagazineCell cell;
position = getPosition(position);
if (null == convertView || convertView.getClass() != MagazineCell.class) {
cell = new MagazineCell(context);
} else {
cell = (MagazineCell) convertView;
}
return cell;
}
Gallery has no special code. I'm using SDK 11 on Acer Iconia TAB A500 running Android 3.1.
Thanks for any hints or comments.

Looks like there's no way to "trick" Gallery to measure scaled cells with their scaled width. So I just used negative spacing - setSpacing(-100); There may be a way via overriding onMeasure method on MagazineCell class and calculate scaled width. But I didn't try this.

after
this.setScaleX(0.7f);
this.setScaleY(0.7f);
add
this.setPivotX(0);
this.setPivotY(0);

Related

How do I fit an exact number of ListView items on screen?

I would like the rows in a ListView to be sized so that exactly six of them can fit on the screen. For that, I would need to know how much vertical space is available to the ListView (not the whole screen). However, no measuring can be done in onCreate() since no views have been rendered yet.
If I make measurements after rendering, the ListView might be drawn and then resized, which may be distracting. What is the smartest way to establish the necessary row height before rendering the ListView?
in onCreate you can get the height of your screen and divide by 6.
Now in your getView you get the reference of the top layout for each item, suppost you have named it's id to root and i.e it's a LinearLayout.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if(view == null){ some inflate }
LinearLayout root = (LinearLayout) view.findViewById(R.id.root);
LayoutParams lp = root.getLayoutParams();
lp.height = screenHeight/6;
root.setLayoutParams(lp);
....
return view;
}
Yes, this assumes the ListView is in fullscreen.
If you have other layouts, you will have to get those height into account.
Then your height will be: int heightForEachItem = (screenHeight - otherlayoutsHeightTogether) / 6;
Turns out that the earliest you can measure a ListView is in the onGlobalLayout() callback.
Here is my example.
params = new AbsListView.LayoutParams(-1,-1);
listview.getViewTreeObserver.addOnGlobalLayoutListener(new OnGlobalLayoutListener(){
#Override
public void onGlobalLayout(){ //this is called just before rendering
params.height = listview.getHeight()/6; // this is what I was looking for
listview.getViewTreeObserver.removeOnGlobalLayoutListener(this); // this is called very often
}
adapter = new ArrayAdapter<...>(int position, ...){
#Override
public View getView(...){
LinearLayout item = new LinearLayout(context);
item.setLayoutParams(params);
// add text, images etc with getItem(position) and item.addView(View)
return item;
}
}
listview.setAdapter(adapter);

Get the ListView's width in the Array Adapter

I have a ListView which will be either full screen width (phone) or roughly 1/3 of the width if it's a landscape tablet. In the List it will display an imaged on a remote server.
Obviously the image can take some time to download the image, so, in the JSON data, I have an average colour of the image as hex, and the ratio of the image. What I want is, in the adapter, to fill the image with the average colour at the right size. I've got the colour part down, using this code
final ColorDrawable cd = new ColorDrawable(Color.parseColor(blog.getAverageColor()));
Picasso.with(getContext()).load(blog.getFullPath()).placeholder(cd).into(img);
However, I can't get the size to work. My original idea was to call getWidth() on the view, and times it by blog.getRatio(), then set the images height to that, and it's width to the width of the view.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (view == null) {
view = getLayoutInflater(null).inflate(r, parent, false);
}
if (view == null) {
return null;
}
int width = view.getWidth();
However, width is always 0. How can I get the width of the view? Or is this just not possible to do like this?
You can get width of listView by call parent.getWidth(). parent is a view that your view will be attached to. So your view will have same sizes.
view.getWidth() returns 0 because at this point your view isn't really added to ListView.

Setting ImageView width and height before drawing in a ListView adapter

I have an adapter to a ListView is a list of ImageViews. I am using a stretch to make the image fil the imageview so I can take smaller images and make them larger on the screen, however the ImageView normally just uses wrap_content and this is an issue because the images just show up as their normal width and height. Is there any way I can set the height and width of a view before drawing it because as in this case I do not have control over the view after it has been drawn. Here is my aapter method:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
String currentImage = getItem(position);
ScaleType scaleType = ScaleType.FIT_CENTER;
float screenWidth = parent.getResources().getDisplayMetrics().widthPixels;
if (convertView == null) {
convertView = new ImageView(parent.getContext());
}
// WHAT I WOULD LIKE TO BE ABLE TO DO, but this returns null pointer exception
// convertView.getLayoutParams().width = (int) screenWidth;
// convertView.getLayoutParams().height = (int) ((float)(screenWidth/currentImage.getWidth())*currentImage.getHeight());
((ImageView) convertView).setScaleType(scaleType);
((ImageView) convertView).setImageBitmap(MainActivity.cache.getBitmap(currentImage));
return convertView;
}
How about something like someView.setHeight() and someView.setWidth()? Or someView.setLayoutParams()? You could add either of these to the overridden getView() callback and it should take care of your problem.
You could also Create a Custom View and override something like getMeasuredWidthAndState(). (I think that's one of the right methods, but I'm not one hundred percent sure.) You could create a width class variable and a height class variable that all instances of your custom ImageView would use. However, that might be a bit much if you just want to set the layout width and height though.

Android - Gallery of ImageViews with background images?

I am new to Android development, but familiar with the concept of views, controls, objects, XML layouts, C#, etc.
I'm trying to create a horizontally scrolling "list" of images using as much native functionality as possible. (I'm not adverse to using custom components, but I'm trying to learn and optimize as much as possible before hacking something together.)
I currently have a Gallery with an adapter tied to it. The adapter is creating ImageViews as seen in many basic tutorials. On each pass of the adapter, I'm setting the background image for the ImageView. My hope was that I'd be able to position the foreground image to lay on top of the background image at a specific X/Y position. Unfortunately, I haven't made it past the point of getting the background image to behave the way I'd like it to.
Is this even possible with a simple Gallery and an ImageView? Or, do I need to build a custom control of some sort (possibly using nested layouts?) and use that control on each iteration of the adapter?
Any help will be greatly appreciated.
Here's what I'm seeing...
http://philaphan.com/public/stackoverflow/gallery1.png
...and what I'd like to see...
http://philaphan.com/public/stackoverflow/gallery2.png
Here's my code:
public class MyAdapter extends BaseAdapter
{
private Context mContext;
public MyAdapter(Context c)
{
mContext = c;
}
public int getCount()
{
return App.myList.size();
}
public Object getItem(int position)
{
return position;
}
public long getItemId(int position)
{
return position;
}
public View getView(int position, View convertView, ViewGroup parent)
{
String imagePath = App.myList.get(position).thumbnail;
ImageView i = new ImageView(mContext);
i.setLayoutParams(new Gallery.LayoutParams(150, 150));
i.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
i.setBackgroundResource(R.drawable.image_bk5);
//i.setBackgroundColor(Color.BLACK);
File f = new File(imagePath);
if (!f.exists())
{
i.setImageResource(R.drawable.image_missing);
}
else
{
Bitmap bmp = BitmapFactory.decodeFile(imagePath);
i.setImageBitmap(bmp);
}
return i;
}
}
I think you can use:
i.setPadding(50, 50, 50, 50); //setpadding(left,top,right,bottom)
Try to use this..
replace i.setScaleType(ImageView.ScaleType.CENTER_INSIDE); with i.setScaleType(ImageView.ScaleType.FIT_XY);
or check your background image . I think your background image width creating problem.
I was able to work around this by using a HorizontalScrollView with a LinearLayout nested within it. I then programmatically add two ImageViews -- one for the background and one for the foreground -- and I position the foreground at whatever X/Y that I choose.
I'd still be interested in knowing if this can be done within a Gallery control, if anyone sees this at a later date.
As a general rule, if you want to add a background image to any kind of inflated gallery or ArrayAdapter or BaseAdapter, then - Make sure that the background image is defined in the parent layout, or parent view, for example the main layout, using the attribute "android:background="#drawable/backupimage".
Do not set the background in the XML representing the custom-row/object-view of the repeating instances.
This way the background image will be displayed only once, appearing static behind all inflated objects, and not duplicated again and again on every single row/object.

ListView: convertView / holder getting confused

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

Categories

Resources