GridView Stretching ImageView Non-Uniformly - android

I have a GridView that I am using to display a row of 4 images, each image is 200 x 200 pixels. Here is the layout 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=".MainActivity" >
<GridView
android:id="#+id/myGridView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:numColumns="4" >
</GridView>
</RelativeLayout>
When I run my app here is what the images look like:
As you can see the images are getting scaled (narrowed) to fit the screen.
How do I make it so the images are stretched both vertically and horizontally to maintain the correct aspect ratio?
Note that I am using an adapter to draw the images:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
if (convertView == null) {
imageView = new ImageView(context);
} else {
imageView = (ImageView) convertView;
}
imageView.setBackgroundResource(imageIds[position]);
return imageView;
}

I got the same issue in last weak.Use my image view class and solve this issue.
public class iv_autoSizedImageView extends ImageView {
public iv_autoSizedImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
try {
getLayoutParams().height = getMeasuredWidth();
} catch (Exception e) {
// TODO: handle exception
}
}
}
layout.xml
<com.sample.test.iv_autoSizedImageView
android:id="#+id/IV_NEWS_IMAGE"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>

Related

How to set width and height of cell item in GridView programmatically in Android

I am trying to set a dynamic width and height of my GridView's items, this is my code:
class GridAdapter extends BaseAdapter {
private Context context;
private GridAdapter(Context context, List<ParseObject> objects) {
super();
this.context = context;
}
// CONFIGURE CELL
#Override
public View getView(int position, View cell, ViewGroup parent) {
if (cell == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
cell = inflater.inflate(R.layout.cell_post_search, null);
}
//-----------------------------------------------
// MARK - INITIALIZE VIEWS
//-----------------------------------------------
ImageView postImg = cell.findViewById(R.id.cpsPostImg);
ImageView videoicon = cell.findViewById(R.id.cpsVideoIcon);
...
return cell;
}
#Override public int getCount() { return postsArray.size(); }
#Override public Object getItem(int position) { return postsArray.get(position); }
#Override public long getItemId(int position) { return position; }
}
// Set Adapter
postsGridView.setAdapter(new GridAdapter(ctx, postsArray));
// Set number of Columns accordingly to the device used
float scalefactor = getResources().getDisplayMetrics().density * screenW/3; // LET'S PRETEND MY screenW = 720, this value whoudl, be 240, which is the width i need for my cell
int number = getWindowManager().getDefaultDisplay().getWidth();
int columns = (int) ((float) number / scalefactor);
postsGridView.setNumColumns(columns);
Log.i(Configurations.TAG, "SCALE FACTOR: " + scalefactor);
And here's my custom cell_post_search.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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="match_parent">
<RelativeLayout
android:id="#+id/cpsCellLayout"
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true">
<ImageView
android:id="#+id/cpsPostImg"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:background="#c1c1c1"
android:scaleType="centerCrop"/>
<ImageView
android:id="#+id/cpsVideoIcon"
android:layout_width="44dp"
android:layout_height="44dp"
android:layout_alignEnd="#+id/cpsPostImg"
android:layout_alignParentTop="true"
android:layout_marginRight="5dp"
android:layout_marginTop="5dp"
android:visibility="invisible"
app:srcCompat="#drawable/play_butt"/>
<ImageView
android:id="#+id/cpsWhiteFrame"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:srcCompat="#drawable/white_frame"/>
</RelativeLayout>
</RelativeLayout>
I get 480.0 as scale factor in my Logcat, which is not the right size I need (in my case it should be 240). Anyway, I've also tried to do this:
int columns = (int) ((float) number / (scalefactor/2));
So the scalefactor = 240, but it doesn't matter, because I need my cell's item to be square size, so basically: WIDTH = screenWidth/3, HEIGHT = screenWidth/3.
It doesn't work properly, my GridView shows 3 columns but cells get stretched in width - height looks fine - as shown here:
Is there a way to edit my code and make cells size correctly, as square images, 3 columns, based on the device size?
Try This
class GridAdapter extends BaseAdapter {
private Context context;
private GridAdapter(Context context, List<ParseObject> objects) {
super();
this.context = context;
}
// CONFIGURE CELL
#Override
public View getView(int position, View cell, ViewGroup parent) {
if (cell == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
cell = inflater.inflate(R.layout.cell_post_search, null);
}
//-----------------------------------------------
// MARK - INITIALIZE VIEWS
//-----------------------------------------------
ImageView postImg = cell.findViewById(R.id.cpsPostImg);
ImageView videoicon = cell.findViewById(R.id.cpsVideoIcon);
DisplayMetrics displayMetrics = new DisplayMetrics();
((Activity) mContext).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int width = displayMetrics.widthPixels;
postImg.getLayoutParams().height = width / 3;
...
return cell;
}
#Override public int getCount() { return postsArray.size(); }
#Override public Object getItem(int position) { return postsArray.get(position); }
#Override public long getItemId(int position) { return position; }
}
Also, in your XML layout, add android:numColumns="3":
<GridView
android:id="#+id/upPostsGridView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:numColumns="3"/>

How to set ImageView height and width before image is loaded with Picasso inside Recycerview StaggeredGridLayout

I am looking to set the ImageView height before loading the image with Picasso. Trying to prevent the parent view from changing its height to the image. I am getting a height and width of the image and setting it inside of of Picasso and then scaling it down.
How do I scale the ImageView based on the "webformatHeight" and "webformatWidth" before loading the image with Picasso to prevent resizing.
Data
{
...
"hits":[
{
"webformatHeight":426,
"webformatWidth":640,
"webformatURL":"https://pixabay.com/get/eb32b5062dfd013ed95c4518b74a4291ea77ead204b0144190f8c478a2ebb3_640.jpg",
...
},
...
]
}
Recycler Implementation
RecyclerView recycler = (RecyclerView) findViewById(R.id.recycler);
mPixabayAdapter = new PixabayAdapter();
recycler.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL));
recycler.setAdapter(mPixabayAdapter);
ViewHolder
class ViewHolder extends RecyclerView.ViewHolder {
private ImageView mImage;
private TextView mTitle;
private ViewHolder(View view) {
super(view);
mImage = view.findViewById(R.id.image);
mTitle = view.findViewById(R.id.title);
}
void bindView() {
ColorDrawable[] shotLoadingPlaceholders = new ColorDrawable[]{new ColorDrawable(ContextCompat.getColor(itemView.getContext(), R.color.background_light))};
Hit hit = mHitList.get(getAdapterPosition());
mTitle.setText(hit.getUser());
Picasso
.with(mImage.getContext())
.load(hit.getWebformatURL())
.placeholder(shotLoadingPlaceholders[0])
.resize(hit.getImageWidth(), hit.getImageHeight())
.priority(Picasso.Priority.HIGH)
.onlyScaleDown()
.into(mImage);
}
}
XML
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="4dp">
<ImageView
android:id="#+id/image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true" />
<TextView
android:id="#+id/title"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_below="#+id/image"
android:background="#color/background_light"
android:fontFamily="sans-serif-medium"
android:gravity="center_vertical"
android:maxLines="1"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:textColor="#color/white_light"
android:textSize="13sp" />
</RelativeLayout>
Calc the aspect ratio of your image by width/height and wrap your ImageView inside something like this:
public class RelativeSizeLayout extends FrameLayout {
private float aspectRatio = 1.77f;
public RelativeSizeLayout(Context context) {
this(context,null);
}
public RelativeSizeLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RelativeSizeLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public boolean shouldDelayChildPressedState() {
return false;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = MeasureSpec.getSize(widthMeasureSpec);
heightMeasureSpec = MeasureSpec.makeMeasureSpec((int) (width / aspectRatio), MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
public void setAspectRatio(float ratio) {
aspectRatio = ratio;
}
}
you can set the layoutParams of the ImageView on the bindView with the width and hight the Hit class like this.
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(hit.getImageWidth(), hit.getImageHeight());
mImage.setLayoutParams(layoutParams);
regards.

Adjust GridView with ImageViews to different screen sizes, Android

I'd so appreciate if someone could advise on below.
My GridView has 3 columns that will be filled with ImageViews:
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/grid_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:layout_marginRight="10dp"
android:layout_marginLeft="10dp"
android:numColumns="3"
android:columnWidth="0.3dp"
android:horizontalSpacing="20dp"
android:verticalSpacing="20dp"
android:stretchMode="columnWidth">
</GridView>
The Adapter that adds ImageViews into the grid cells:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView = new ImageView(mContext);
imageView.setImageResource(mThumbIds.get(position));
imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
imageView.setLayoutParams(new GridView.LayoutParams(300, 300));//problem here
return imageView;
}
My images are all of the size 358x385px.
It works fine on bigger screens but fails on smaller ones (for example 4", 800x480).
I'm not sure how to set LayoutParams to be like 1/3 of the screen width and the height to form a square.
I wouldn't like to add more images with appropriate sizes for different screen densities, instead I want to resize ImageViews only.
Follow this code for squre gridview to all device compitible.
Step :1 Create one class SquareImageView.class that extends Imageview.
public class SquareImageView extends ImageView {
public SquareImageView(Context context) {
super(context);
}
public SquareImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SquareImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(getMeasuredWidth(), getMeasuredWidth()); //Snap to width
}
}
Step :2 Change your adapter like this.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
SquareImageView imageView = new SquareImageView (mContext);
imageView.setImageResource(mThumbIds.get(position));
imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
return imageView;
}
And your xml like this
<GridView
android:id="#+id/grid_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:numColumns="3"
android:gravity="center"
android:padding="3dp"
android:stretchMode="columnWidth"
android:horizontalSpacing="2dp"
android:verticalSpacing="2dp"
/>
And test in small screen device..It will help you

GridView to make square board

I'm trying to make a square board with 5 x 5 grid using gridview. Here is my code:
<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" >
<GridView
android:id="#+id/squareBoard"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:numColumns="5"
/>
</RelativeLayout>
This is the Adapter I used:
private class TextViewAdapter extends BaseAdapter {
private Context mContext;
private int mWidth, mHeight;
public TextViewAdapter(Context c, int width, int height) {
mContext = c;
mWidth = width;
mHeight = height;
}
public int getCount() {
return mWidth * mHeight;
}
public TextView getItem(int position) {
return null;
}
public long getItemId(int position) {
return 0;
}
// create a new ImageView for each item referenced by the Adapter
public View getView(int position, View convertView, ViewGroup parent) {
TextView tv = null;
if (convertView == null) { // if it's not recycled, initialize some attributes
tv = new TextView(mContext);
tv.setText("" + position);
tv.setGravity(Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL);
tv.setLayoutParams(new GridView.LayoutParams(100, 100));
tv.setWidth(100);
tv.setBackground(getResources().getDrawable(R.drawable.letter_box));
} else {
tv = (TextView) convertView;
}
return tv;
}
}
and this is the letter_box.xml of the textview background
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<solid
android:color="#android:color/white" >
</solid>
<stroke
android:width="1dp"
android:color="#android:color/black" >
</stroke>
</shape>
So far, i managed to display boxes, but there's always horizontal space between columns. I want them to be like a chess board.
Can anyone help me?
Create your own class MyGridView which extends GridView.
Override its onMeasure(...) method and set height == width, like so:
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
}
Then, create your own GridViewItem extending a View subclass e.g. TextView or ImageView etc. Override its onMeasure(...) method in the same way.
MyGridViewand its items will all appear square.
On your GridView, you can set the vertical spacing and the horizontal spacing that is between two items. Try setting those to 0dp.
<GridView
android:id="#+id/squareBoard"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:verticalSpacing="0dp"
android:horizontalSpacing="0dp"
android:numColumns="5"
/>

How to make a list of square buttons with autoresize?

I am developing an app that displays a page with a variable number of square buttons, like the second picture of "Square MIUI":
Square MIUI on APP store
I need displaying only three columns of square buttons, and make the entire list scrollable.
I'm trying first with plain XML:
<?xml version="1.0" encoding="utf-8"?>
<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" >
<ScrollView
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_gravity="center"
android:layout_weight="1.19"
android:orientation="horizontal" >
<TableLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" >
<TableRow
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:layout_weight="1" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="Title"/>
</TableRow>
<TableRow
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<!-- Icon buttons here -->
</TableRow>
</TableLayout>
</ScrollView>
<Button
android:layout_width="fill_parent"
android:layout_height="48dp"
android:text="Button" />
</LinearLayout>
For every button (4 TableRow of 3 buttons, images are square .png made with Eclipse icon generator)
EDIT: checked, icons of all screen densities are square
<Button
android:layout_margin="4dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="image"/>
but the buttons on my tablet are square, and on my phone are wider than tall (stretched on X-axis).
What I'm doing wrong?
TODO: code a variable button number.
Thanks in advance.
EDIT:
I tried this code:
private void squareButton() {
square(R.id.b1);
square(R.id.b2);
....
square(R.id.b<N>);
}
private void square(int id) {
ImageButton temp=(ImageButton) findViewById(id);
int l=temp.getWidth();
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int Measuredwidth = metrics.widthPixels;
l=(int) (Measuredwidth/4);
temp.setMaxWidth(l);
temp.setMaxHeight(l);
temp.setMinimumWidth(l);
temp.setMinimumHeight(l);
LayoutParams param = temp.getLayoutParams();
param.width = l;
param.height = l;
temp.setLayoutParams(param);
temp.requestLayout();
}
But I'm still getting weird buttons on phone (Gingerbread)...
I can't rely only on the auto-sized icons (too little on my tablet, too big on my phone)
EDIT:
I'm looking for a code that:
squares button
has user-definable width
works with Gingerbread
In my case, button_width = widthPixels/4;
Thank you in advance.
Implements you own square button class like this:
public class SquareButton extends Button {
public SquareButton(Context context) {
super(context);
}
public SquareButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SquareButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(getMeasuredWidth(), getMeasuredWidth()); // Snap to width
}
}
Finally, I found a solution using GridView.
First, I follow the GridView tutorial
Then I got some code from other answers.
Now this code creates a scrollable and clickable big square icon list, resized according to screen size. When one icon is clicked, changes his image.
Thank you Lubos for your suggestion.
[main activity]
public class Grid extends Activity {
public boolean audio=true;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_grid);
GridView gridview = (GridView) findViewById(R.id.gridview);
gridview.setAdapter(new ImageAdapter(this));
// load icons on grid
ImageAdapter.loadImages(new Integer[] {
R.drawable.ic_blu_voice_on,
R.drawable.ic_blu_help,
R.drawable.ic_blu_save,
R.drawable.ic_blu_load
});
gridview.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View imgView, int position, long id) {
ImageView image=(ImageView) imgView;
switch (position) {
case 0:
// switch voice icon on/off when clicked
image.setImageResource(voice());
break;
}
Toast.makeText(Grid.this, "" + position, Toast.LENGTH_SHORT).show();
}
});
}
private int voice() {
audio=!audio;
if (audio) return R.drawable.ic_blu_voice_on;
return R.drawable.ic_blu_voice_off;
}
}
[imageadapter.java]
public class ImageAdapter extends BaseAdapter {
private Context mContext;
// reference to images (dummy)
private static Integer[] mThumbIds = {0,0};
private float px;
public ImageAdapter(Context c) {
mContext = c;
//Calculation of ImageView Size - density independent.
Resources r = Resources.getSystem();
px = r.getDisplayMetrics().widthPixels;
px=px/3;
}
public int getCount() {
return mThumbIds.length;
}
public Object getItem(int position) {
return null;
}
public long getItemId(int position) {
return 0;
}
public static void setImage(int position, int id) {
mThumbIds[position]=id;
}
public static void loadImages(Integer[] images) {
mThumbIds = images;
}
// create a new ImageView for each item referenced by the Adapter
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);
imageView.setLayoutParams(new GridView.LayoutParams((int)px, (int)px));
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
imageView.setPadding(8, 8, 8, 8);
} else {
imageView = (ImageView) convertView;
}
imageView.setImageResource(mThumbIds[position]);
return imageView;
}
}
[activity_grid.xml]
<RelativeLayout xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_gravity="center_horizontal"
android:orientation="vertical"
tools:context="${packageName}.${activityClass}">
<LinearLayout
android:id="#+id/LinearLayout1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_horizontal"
android:orientation="vertical"
tools:context="${relativePackage}.${activityClass}" >
<TextView
android:id="#+id/testo1"
android:layout_width="fill_parent"
android:layout_height="48dp"
android:gravity="center_horizontal"
android:text="#string/hello_world"
android:textSize="30sp" />
<GridView
android:id="#+id/gridview"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:columnWidth="120dp"
android:gravity="center"
android:numColumns="auto_fit"
android:stretchMode="spacingWidthUniform">
</GridView>
<Button
android:id="#+id/button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/hello_world"
android:textSize="30sp" />
</LinearLayout>
</RelativeLayout>

Categories

Resources