I'm getting frustrated about this:
When I define a custom ListView Layout,
Android Studio doesn't keep the background drawable I set in there.
Tried many things, and setting background programmatically doesn't work
since it's ignoring the layout_width which must be set to "wrap_content".
Actual style of background
Result without coding
If anyone could help me, I'd be very grateful !:)
EDIT:
I'm creating a Messenger and I want to display messages in a similar way to WhatsApp, where messages are shown in a listView. Depending on message is sent or received, items should be aligned ParentStart or ParentEnd.
But more importantly, if a message only contains a few chars, I don't want the ListItem Background to fill the entire screen, so it should be set dynamically.
I thought I could achieve this through simply setting wrap content in the parent layout file.
Files look like this:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_alignParentEnd="true">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentTop="true"
android:layout_marginBottom="4dp"
android:layout_marginTop="4dp"
tools:background="#drawable/background_message_sent">
//Here are TextViews
</LinearLayout>
</RelativeLayout>
Here is my ListViewAdapter, where I set background
(#drawable/background_message_sent/received) programmatically.
However, this covers the entire width of ListView, regardless of message length.
#Override
public View getView(int pos, View convertView, ViewGroup parent) {
int currentUserID = 1;
int senderID = messagesArrayList.get(pos).getSenderID();
if (senderID == currentUserID){
View v = View.inflate(context, R.layout.layout_chat_message_sent, null);
v.setBackgroundResource(R.drawable.background_message_sent);
TextView tvMessageText = v.findViewById(R.id.tvMessageText);
TextView tvTimeStamp = v.findViewById(R.id.tvTimeStamp);
tvMessageText.setText(messagesArrayList.get(pos).getMessageText());
tvTimeStamp.setText(messagesArrayList.get(pos).getTimeStamp());
return v;
}
else {
View v = View.inflate(context, R.layout.layout_chat_message_received, null);
v.setBackgroundResource(R.drawable.background_message_received);
TextView tvMessageText = v.findViewById(R.id.tvMessageText);
TextView tvTimeStamp = v.findViewById(R.id.tvTimeStamp);
tvMessageText.setText(messagesArrayList.get(pos).getMessageText());
tvTimeStamp.setText(messagesArrayList.get(pos).getTimeStamp());
return v;
}
}
Well, after trying, I got the solution if anyone comes to this point:
You have to set your background drawable directly for each TextView, not for Parent Layouts.
These two Lines finally solved everything ^^
android:maxEms="14"
android:background="#drawable/background_message_sent"
<TextView
android:id="#+id/tvMessageText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:layout_marginEnd="0dp"
android:layout_marginTop="5dp"
android:layout_weight="0.22"
android:text="42456456456546"
android:textColor="#color/tentakelPrimary"
android:maxEms="14"
android:background="#drawable/background_message_sent"/>
I have a problem with spacing in my Android app: Unwanted space between columns.
I noticed similar questions have been asked on stackoverflow before, but none seemed to match exactly my case.
Here's what it looks like (using the code below)... http://i.imgur.com/OXIms9n.png
From my PlayAdapter.java
#Override
public View getView(int index, View view, ViewGroup viewGroup) {
ImageView imageView = new ImageView(context1);
imageView.setImageBitmap(images[index]);
return imageView;
}
From my Spacing.java
GridView gridView = (GridView) findViewById(R.id.gridview2);
final PlayAdapter PlayAdapter1 = new PlayAdapter(this, images);
gridView.setAdapter(PlayAdapter1);
gridView.setNumColumns(numCols);
gridView.setColumnWidth(width);
(numCols and width are determined programmatically elsewhere )
The GridView:
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/gridview2"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
android:horizontalSpacing="2dp"
android:verticalSpacing="2dp"
android:layout_gravity="center"
android:stretchMode="spacingWidthUniform">
</GridView>
So, if stretchMode is set to "columnWidth", "spacingWidth" or
"spacingWidthUniform" there is too much space between
the columns of the grid. See the imgur link above for the result.
Here's a solution I already tried instead:
If stretchMode is changed to "none", the grid is centered
vertically in portrait mode, but not horizontally in
landscape mode. Looks like this: http://i.imgur.com/Di6TgS2.png
Changing the settings for gravity and
layout_gravity did not help, nor did making a LinearLayout
around the gridview.
Any other ideas what to do?
I have to show 7 icons on the home screen of my application .To do this i have arranged the icons on the grid view using image view to show images .On emulator it looks absolutely fine but images shrink and look blur ,when i deploy the application on LG Optimus p350 please help me how to show the images clearly of actual size :
The code i tried are :
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/gridview" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:columnWidth="61dp"
android:numColumns="3" android:verticalSpacing="10dp"
android:horizontalSpacing="10dp" android:stretchMode="spacingWidthUniform"
android:gravity="center" android:layout_gravity="center" />
icon size is 61*80
EDIT :
<supports-screens android:smallScreens="true"
android:normalScreens="true" android:largeScreens="true"
android:anyDensity="true"/>
Please see the image and the code On emulator the output is shown like this.I want to show output on device also with this clarity.Please guide
see second screen shot (blur on qvga emulator) and please guide me how to correct it ..
The images don't appear blurred to me. They are just smaller due to higher screen resolution. But the text does look blurred.
So I would suggest to use a combination of ImageView and TextView. To separate the text and image. The text will be scaled appropriately.
You can also provide multiple image sets for different resolutions.
EDIT:
You can create a grid item layout similar to this:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:gravity="bottom"
android:layout_width="wrap_content"
android:layout_gravity="bottom">
<ImageView android:id="#+id/thumbnailImage"
android:layout_height="70dp"
android:layout_width="fill_parent"
android:gravity="center_horizontal" />
<TextView android:id="#+id/thumnailTitle" android:text="TextView"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="fill_parent"
android:gravity="center_horizontal|bottom" />
</LinearLayout>
Create a custom grid adapter extending BaseAdapter class:
public class MyGridAdapter extends BaseAdapter
{...}
associate the adapter with your grid:
adapter = new MyGridAdapter();
GridView gridView = (GridView) findViewById(R.id.gridView);
gridView.setAdapter(adapter);
Then it is just a matter of filling the items to the grid with the getView adapter method:
public View getView(int position, View convertView, ViewGroup parent)
{
// assuming the grid item layout is named "grid_item"
View view = inflater.inflate(R.layout.grid_item, null);
TextView text = (TextView) view.findViewById(R.id.thumnailTitle);
text.setText("Test");
ImageView thumbnail = (ImageView) view.findViewById(R.id.thumbnailImage);
...
Are you providing multiple resolution resources? Read carefully this article about Supporting Multiple Screens.
I don't think the images shrink, they only look smaller because your phone has a higher density or resolution than the emulator you were testing on.
A quick question:
In ListView I use this code:
list.addHeaderView(headerView);
How to deal with it when working on gridview?
Thanks.
There is no support for header or footer views with GridView, sorry.
There is a quite good implementation of GridView with header support in Google Photos application, as it's OSS code you can use it as is or take it as a reference for your own implementation:
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android-apps/4.3_r2.1/com/android/photos/views/HeaderGridView.java
Basic idea is quite simple - WrapperAdapter creates an fake row by increasing number of items by number of columns and then return a header view for the item.
You can use this. The footer appears/hides at the bottom of the grid when you reach/leave the last number of items. It does not actually scroll, but I hardly notice the difference.
In your activity/fragment's onCreate/onCreateView you add an OnScrollListener to the GridView:
....
GridView gridview = (YMAnimatedGridview) v.findViewById(R.id.my_gridview);
gridview.setAdapter(adapter);
final View footerView = mainView
.findViewById(R.id.my_grid_footer_view);
gridview.setOnScrollListener(new GridView.OnScrollListener() {
#Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
if (firstVisibleItem + visibleItemCount == totalItemCount) {
// last item in grid is on the screen, show footer:
footerView.setVisibility(View.VISIBLE);
} else if (footerView.getVisibility() != View.GONE) {
// last item in grid not on the screen, hide footer:
footerView.setVisibility(View.GONE);
}
}
#Override
public void onScrollStateChanged(AbsListView view,
int scrollState) {
}
});
Your layout should look something like the below. Notice the layout_weight (and layout_height) parameter in the gridview, it is needed to make the correct space for the footer when it becomes visible.
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<GridView
android:id="#+id/my_gridview"
android:layout_width="match_parent"
android:layout_height="0dp"
android:columnWidth="160dp"
android:gravity="center_horizontal"
android:horizontalSpacing="12dp"
android:numColumns="auto_fit"
android:layout_weight="1"
android:stretchMode="columnWidth"
android:verticalSpacing="6dp" />
<TextView
android:id="#+id/my_grid_footer_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:layout_marginBottom="8dp"
android:orientation="horizontal"
android:visibility="gone"
android:text="footer text here" >
</TextView>
</LinearLayout>
Sample code:
GridViewWithHeaderAndFooter gridView = (GridViewWithHeaderAndFooter) v.findViewById(R.id.ly_image_list_grid);
LayoutInflater layoutInflater = LayoutInflater.from(this);
View headerView = layoutInflater.inflate(R.layout.test_header_view, null);
View footerView = layoutInflater.inflate(R.layout.test_footer_view, null);
gridView.addHeaderView(headerView);
gridView.addFooterView(footerView);
Gradle build:
.
compile 'in.srain.cube:grid-view-with-header-footer:1.0.12'
You'd have to use a ListView, then make each row of the list look like it's actually a row of a grid. So if you have a 3 column grid, you'd make a layout for the ListView that looks like 3 columns. You'd then have to modify certain aspects of the Adapter to make it work so that each ListView row actually represents 3 lines of data -- so you know, getCount()/3 type stuff.
How about checking for the "0" index element in your adapter? You can inflate the custom view for the first one.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if(view==null){
if(position==0){
// ...inflate header view
}else{
// ...do as usual
Haven't tested it, but should work.
You can use AsymmetricGridView and specify headers/footers with a bigger rowSpan so they would take the entire row.
Why don't you change the appearance of the cells for the first rows? if you know how many columns you have, you know how many items will appear in the header = number of columns.It works for me
You could use this library, http://tonicartos.github.io/StickyGridHeaders/
which allows you to create headers that are sticky (for grouping the list and keeping the header visible for the current group). You can turn off the sticky feature as well.
There is a way to accomplish the desired functionality WITHOUT using a library or anything.
EDIT: Just borrow the HeaderGridView Implementation by google, see Here
You could also customize it for footer. The below suggestion is just too complicated and required more tweaking.
Without going into specific details, all you need to do is this.
1) Subclass GridView
2) override onScrollChanged
3) Calculate the offset everytime it scrolls
4) Set the parentView(view that contains the headerView and gridview) translation y to -Offset.(view.setTranslationY(-offset). Also have an if statement to that once it reaches a certain offset it would stop scrolling.
5) obviously you want to structure this well so your gridview can have a method like attachToGridview(View view). I have a complete implementation of this which works.
See Scroll offset of GridView for help on getting offset since GridView has a bug were the views get recycled.
<?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">
<com.test.Breadcrumbs android:layout_width="fill_parent" android:layout_height="100dp" />
<GridView
android:id="#+id/grid"
android:numColumns="auto_fit"
android:gravity="center"
android:stretchMode="columnWidth"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:verticalSpacing="10dp"
android:horizontalSpacing="10dp">
</GridView>
</LinearLayout>
and Breadcrumbs:
public class Breadcrumbs extends LinearLayout {
public Breadcrumbs(final Context context, final AttributeSet attrs) {
super(context, attrs);
final LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
layoutView = inflater.inflate(R.layout.breadcrumbs, this, true);
works fine, scroll for grid works as well.
I am attempting to write code that would allow me to have 1-2 views at the top of a listview that are of a different arrangement than the other views in the listview. I decided to try the method of using addHeaderView() for the 1-2 views that will differ in display.
I have two xml layout files, one that defines the view format that most of the listview views will fall under (list_image_checkbox_row.xml) and one for the Header Views (catalog_featured_row.xml). The adapter constructor uses list_image_checkbox_row as its resource in the constructor.
I used a Thread to set the adapter and load the views. I am able to programmatically create views and use addHeaderView to at them to the listview (using the same image resource), but I get errors when I try to use addHeaderView on a view I have inflated from a layout xml file.
handler.post(new Runnable() {
#Override
public void run() {
lv = (ListView)findViewById(R.id.sources_list);
Activity context = BrowseSourceActivity.this;
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.catalog_featured_row, null);
ImageView feat_view = (ImageView) view.findViewById(R.id.image);
feat_view.setImageResource(R.drawable.arrow);
lv.addHeaderView(feat_view);
setListAdapter(array);
}
});
I get a force close error and haven't been able to find anything in logcat (when I was trying to debug yesterday I got a NullPointerException). If I comment out the lv.addHeaderView(feat_view) line, the application does not force close on me. Here is the code for featured_catalog_row.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="70dip"
android:padding="5dip">
<ProgressBar android:id="#+id/spinner"
android:indeterminate="true"
android:layout_width="30dip"
android:layout_height="30dip"
android:layout_centerInParent="true"
/>
<ImageView android:id="#+id/image"
android:gravity="center"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</RelativeLayout>
Any suggestions for how to get the inflater to work?
Perhaps you should store lv in an instance variable instead of looking it up dynamically. Note that both View and Activity have a method called findViewById, and so your results will depend on how your code is organized.