Why setImageResource displays nothing? - android

I would like to display an icon in my ListView depending on the database value. I follow this answer to do so.
But in result nothing is displayed. Here is what I have in my row.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="#+id/movie_subscribed_icon"
android:padding="3dip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/star_off"/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView android:id="#+id/movie_name"
...
and here is the code:
movies.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
#Override
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
int viewId = view.getId();
switch(viewId) {
case R.id.movie_name:
int readValue = cursor.getInt(cursor.getColumnIndexOrThrow(MoviesDbAdapter.KEY_READ));
if (readValue == 1) { // viewed movie item
TextView movieName = (TextView) view;
movieName.setTextColor(Color.GRAY);
}
break;
case R.id.movie_subscribed_icon:
int subscribedValue = cursor.getInt(cursor.getColumnIndexOrThrow(MoviesDbAdapter.KEY_READ));
if (subscribedValue > 0) { // subscribed movie item
ImageView movieIcon = (ImageView) view;
movieIcon.setImageResource(R.drawable.star_off);
}
break;
}
return false;
}
} );
I especially use the same icon in my code as default one.
What is wrong here? (I have star_off in drawable-hdpi and drawable-mdpi folders only)
Upd. the following code works well:
movieIcon.setImageDrawable(getResources().getDrawable(R.drawable.star_off));

public void setImageResource (int resId) : This does Bitmap reading and decoding on the UI thread, which can cause a latency hiccup. If that's a concern, consider using setImageDrawable(Drawable) or setImageBitmap(Bitmap) and BitmapFactory instead.
Try invalidating your image view, or use one of the alternatives that the documentation suggests.

I've found a solution in another question.
Basically the setViewValue() method
should return false until it is called
for your image view. Then it should
set the data in the view and return
true. The return value indicates
whether the ViewBinder set the view
itself or whether the adapter should
bind the data itself via its default
behavior.
Since I didn't return true, it worked incorrectly.
Now it works perfectly.

Attempt #2.
Why don't you try this...
ImageView movieIcon = (ImageView)findViewById(R.id.movie_subscribed_icon);
movieIcon.setImageResource(R.drawable.star_off);
I think you may be creating a new ImageView instead of grabbing the one that already exists in your layout.

This piece of code solves the problem :
ImageView movieIcon = (ImageView)findViewById(R.id.movie_subscribed_icon);
Drawable drawable = this.getResources().getDrawable(R.drawable.android);
movie_subscribed_icon.setBackgroundDrawable(drawable);

This works...
In the XML, do not use "src" attribute for ImageView drawable. Instead, use "background".
Like this:
<ImageView
android:id="#+id/maximize_inbox_window"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/ic_action_original_image"
android:layout_gravity="center_vertical"
android:clickable="true"
android:paddingRight="5dp" />
And the Java code to change the image at runtime is here...
ImageView img = (ImageView) rootView.findViewById(R.id.image_view_name);
img.setBackground(getResources().getDrawable(R.drawable.resource_id));
img.invalidate();
Substitute the image_view_name with your ImageView in the XML and the resource_id with your name of the image in the drawable folders. Don't forget to call invalidate().
Note: Do not use setBackgroundDrawable() as its deprecated.
Hope this works for others too.

Related

Parse RelativeLayout, Set Content, And Add It To A LinearLayout

Ok... here's my situation.
I have a carousel of images in a HorizontalScrollView - which contains a LinearLayout - in my Activity, like so:
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/slider"
android:scrollbars="none" >
<LinearLayout
android:id="#+id/carousel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
/>
</HorizontalScrollView>
I have a TypedArray, loop through it, and on each run, set these images programatically, add a ClickListener and a Tag, and add this ImageView to the LinearLayout (set in my Activity Layout), like so:
// Get the array
final TypedArray carouselArray = getResources().obtainTypedArray(R.array.carousel_array);
// Populate the Carousel with item
for (int i = 0 ; i < carouselArray.length() ; ++i) {
// Image Item
ImageView outerImage;
// Set the image view resource
if(i == 0) {
outerImage.setImageResource(R.drawable.toy_filter_clear);
}
else {
outerImage.setImageResource(carouselArray.getResourceId(i, -1));
}
// Set Touch Listener
outerImage.setOnTouchListener(this);
final String prepend = "CAROUSEL_";
final String index = String.valueOf(i);
final String tag = prepend.concat(index);
outerImage.setTag(tag);
/// Add image view to the Carousel container
mCarouselContainer.addView(outerImage);
}
But now, I just found out that I have to programatically add a second image to sit inside/on top of the first image at particular coordinates (damn you UI ppl!). I need these to be considered the same image/view essentially, so need to pack them together inside of a layout, I am assuming. So I have made a layout file, like so:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/carousel_item"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:id="#+id/carousel_outer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:src="#drawable/toy_filter_normal"
/>
<ImageView
android:id="#+id/carousel_inner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="#+id/carousel_outer"
android:layout_alignRight="#+id/carousel_outer"
android:layout_marginBottom="10dp"
android:layout_marginRight="5dp"
android:src="#drawable/thumb_nofilter"
/>
</RelativeLayout>
This has the proper positioning, and the default images set on it. So what I want to be able to do is to reach into the Layout file, grab the ImageViews by their ID, overwrite the image if necessary, and then add that RelativeLayout to my LinearLayout at the end of my loop... sounds easy enough, right ?
My first attempt was to do it like this :
RelativeLayout item = (RelativeLayout) findViewById(R.id.carousel_item);
ImageView outerImage = (ImageView) item.findViewById(R.id.carousel_outer);
ImageView innerImage = (ImageView) item.findViewById(R.id.carousel_inner);
... but that gives me a NullPointer on the ImageView...So then I tried to inflate the RelativeLayout first, like this:
LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.carousel_item_layout, null);
ImageView outerImage = (ImageView) view.findViewById(R.id.carousel_outer);
ImageView innerImage = (ImageView) view.findViewById(R.id.carousel_inner);
This gets rid of the NPE's, and (apparently) let's the images be set properly like so:
if(i == 0) {
outerImage.setImageResource(R.drawable.toy_filter_clear);
innerImage.setImageResource(0);
}
else {
outerImage.setImageResource(R.drawable.toy_filter_normal);
innerImage.setImageResource(carouselArray.getResourceId(i, -1));
}
but when I try to add the outerImage ImageView back to the LinearLayout, I get an NPE there:
mCarouselContainer.addView(outerImage);
More to the point, I don't want to add ONLY the one ImageView to the LinearLayout/HorizontalScrollView - I want to somehow pack the resulting images back into the RelativeLayout and add the whole thing back into my LinearLayout... but, it is worth mentioning, that this also gives me an NPE.
What is a guy to do ? Any thoughts appreciated...
Ok... Wow, thanks SO Code Monkey!
I managed to fix this with a one line fix, by adding the inflated View to the LinearLayout instead of the ImageView or the RelativeLayout (which wasn't doing anything), like so:
mCarouselContainer.addView(view);
Don't know why I hadn't tried that before, but I was unclear on whether as it's children were being updated if it would reflect the parent, so to speak... now I know it was.
I'm gonna keep the question up, as I think it's helpful... ?

Small EditText have a setError with a lot of lines

I have a small EditText and I want to display errors (using editText.setError()) in it. In Android API 10 the message is displayed in a lot of lines and it's unreadable. In Android 15 works relatively fine. I attach screenshots to illustrate the problem at the end of the question.
How I can display the error messages in a appropriate mode?
I wrote a little example to reproduce the problem:
The Activity:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
((EditText) findViewById(R.id.b)).setError("A error description and bla bla bla bla bla.");
}
The layout:
<?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="horizontal" >
<EditText
android:id="#+id/a"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1" />
<EditText
android:id="#+id/b"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1" />
<EditText
android:id="#+id/c"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1" />
<EditText
android:id="#+id/d"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1" />
<EditText
android:id="#+id/e"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1" />
<EditText
android:id="#+id/f"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1" />
</LinearLayout>
Device with Android API 10:
Tablet with Android API 15:
Related question. But the answer doesn't work for me.
UPDATE
I executed the same code on two equals simulators except the API level. The results can be seen on the screens. The API 15 still does not fix the error completely. The text is legible but the popup is not in the correct position.
So looking at the source for 2.3.3 the width of the error text is set to slightly less than the width of the TextView it is related to.
They've jimmied around with that for 4.0.3 so that, in your example, the width of the pop-up is correct - but the nature of your layout is such that the pointer is in the wrong place.
I think you've a reasonable example for a bug report against 4.0.3 as I don't think you've got that unusual a use-case.
In order to sort this out though I'd recommend using a TextView that you hide and reveal as necessary. You can set an error image on the edit text as below.
Drawable errorImage = getContext().getResources().getDrawable( R.drawable.your_error_image);
theEditTextInQuestion.setCompoundDrawableWithIntrinsicBounds(errorImage, null, null, null);”
on api 14, TextView use this class;
private static class ErrorPopup extends PopupWindow {
private boolean mAbove = false;
private final TextView mView;
private int mPopupInlineErrorBackgroundId = 0;
private int mPopupInlineErrorAboveBackgroundId = 0;
ErrorPopup(TextView v, int width, int height) {
super(v, width, height);
mView = v;
// Make sure the TextView has a background set as it will be used the first time it is
// shown and positionned. Initialized with below background, which should have
// dimensions identical to the above version for this to work (and is more likely).
mPopupInlineErrorBackgroundId = getResourceId(mPopupInlineErrorBackgroundId,
com.android.internal.R.styleable.Theme_errorMessageBackground);
mView.setBackgroundResource(mPopupInlineErrorBackgroundId);
}
void fixDirection(boolean above) {
mAbove = above;
if (above) {
mPopupInlineErrorAboveBackgroundId =
getResourceId(mPopupInlineErrorAboveBackgroundId,
com.android.internal.R.styleable.Theme_errorMessageAboveBackground);
} else {
mPopupInlineErrorBackgroundId = getResourceId(mPopupInlineErrorBackgroundId,
com.android.internal.R.styleable.Theme_errorMessageBackground);
}
mView.setBackgroundResource(above ? mPopupInlineErrorAboveBackgroundId :
mPopupInlineErrorBackgroundId);
}
private int getResourceId(int currentId, int index) {
if (currentId == 0) {
TypedArray styledAttributes = mView.getContext().obtainStyledAttributes(
R.styleable.Theme);
currentId = styledAttributes.getResourceId(index, 0);
styledAttributes.recycle();
}
return currentId;
}
#Override
public void update(int x, int y, int w, int h, boolean force) {
super.update(x, y, w, h, force);
boolean above = isAboveAnchor();
if (above != mAbove) {
fixDirection(above);
}
}
}
And call like this;
final float scale = getResources().getDisplayMetrics().density;
mPopup = new ErrorPopup(err, (int) (200 * scale + 0.5f), (int) (50 * scale + 0.5f));
mPopup.setFocusable(false);
So Android TextView use your phone density. I tried for change density but i couldn't work because it need root. If you can this, maybe its work. But i guess it is not possible.
I think you should set the width of the edit text as fill parents so that it will take the proper place, otherwise give the width like 200 or 250 dp so that in that particular width your error message will be shown to you.
does those two emulator have the same screen sizes?.. if so, i think it would be appropriate to set the layout_widths and the heights to wrap content for the popup and if the error still persist then define specifically the width and height of the popup
I think a problem might be that the LinearLayout in your XML has no weightSum attribute. I do not know if you can use layout_weight in child views if LinearLayout does not have a weightSum declared. Also, try changing your layout_widths to "wrap_content" and get rid of the layout_weights if that doesnt work.

Adding a simple ScrollView to Gallery causes a memory leak

I've run into what I can only categorize as a memory leak for ScrollView elements when using the Gallery component.
A short background. I've got an existing app that is a photo slideshow app.
It uses the Gallery component, but each element in the adapter is displayed in full-screen.
(full source is available at this link)
The adapter View element consist of an ImageView, and two TextViews for title and description.
As the photos are of a quite high-resolution, the app uses quite a lot of memory but the Gallery has in general manage to recycle them well.
However, when I am now implementing a ScrollView for the description TextView, I almost immediately run into memory problems. This the only change I made
<ScrollView
android:id="#+id/description_scroller"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical"
android:fillViewport="true">
<TextView
android:id="#+id/slideshow_description"
android:textSize="#dimen/description_font_size"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#color/white"
android:layout_below="#id/slideshow_title"
android:singleLine="false"
android:maxLines="4"/>
</ScrollView>
I did a heap dump and could clearly see that it was the Scrollview which was the root of the memory problems.
Here are two screenshots from the heap dump analysis. Note that the ScrollView retains a reference to mParent which includes the large photo I use
PS same problem occurs if I use the TextView's scrolling (android:scrollbars = "vertical" and .setMovementMethod(new ScrollingMovementMethod());
PSS Tried switching off persistent drawing cache, but no different dreaandroid:persistentDrawingCache="none"
Have you tried removing the scroll view whenever it's container view scrolls off the screen? I'm not sure if that works for you but its worth a shot? Alternatively, try calling setScrollContainer(false) on the scroll view when it leaves the screen. That seems to remove the view from the mScrollContainers set.
Also, this question, answered by Dianne Hackborn (android engineer), explicitly states not to use scrollable views inside of a Gallery. Maybe this issue is why?
Just add this -> android:isScrollContainer="false"
<ScrollView
android:id="#+id/description_scroller"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical"
android:fillViewport="true"
android:isScrollContainer="false">
There is some source why this is appear:
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.1_r1/android/view/View.java
the problem is:
setScrollContainer(boolean isScrollContainer)
by default:
boolean setScrollContainer = false;
but in some cases like this
if (!setScrollContainer && (viewFlagValues&SCROLLBARS_VERTICAL) != 0) {
setScrollContainer(true);
}
it can be true, and when it happends
/**
* Change whether this view is one of the set of scrollable containers in
* its window. This will be used to determine whether the window can
* resize or must pan when a soft input area is open -- scrollable
* containers allow the window to use resize mode since the container
* will appropriately shrink.
*/
public void setScrollContainer(boolean isScrollContainer) {
if (isScrollContainer) {
if (mAttachInfo != null && (mPrivateFlags&SCROLL_CONTAINER_ADDED) == 0) {
mAttachInfo.mScrollContainers.add(this);
mPrivateFlags |= SCROLL_CONTAINER_ADDED;
}
mPrivateFlags |= SCROLL_CONTAINER;
} else {
if ((mPrivateFlags&SCROLL_CONTAINER_ADDED) != 0) {
mAttachInfo.mScrollContainers.remove(this);
}
mPrivateFlags &= ~(SCROLL_CONTAINER|SCROLL_CONTAINER_ADDED);
}
}
mAttachInfo.mScrollContainers.add(this) - all view put into ArrayList this lead to leak of memory sometimes
Yes i noticed the problem, sorry for my previous comment, i've tried to empty the Drawables
by setting previous Drawable.setCallBack(null); but didnt work, btw i have nearly the same project, i use ViewFlipper instead of Gallery, so i can control every thing, and i just use 2 Views in it, and switch between them, and no memory leak, and why not you resize the Image before displaying it, so it will reduce memory usage (search SO for resizing Image before reading it)
Try moving "android:layout_below="#id/slideshow_title" in TextView to ScrollView.
Ended up with implementing a workaround that uses a TextSwitcher that is automatically changed to the remaining substring every x seconds.
Here is the relevant xml definition from the layout
<TextSwitcher
android:id="#+id/slideshow_description"
android:textSize="#dimen/description_font_size"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="#+id/slideshow_description_anim1"
android:textSize="#dimen/description_font_size"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="2"
android:textColor="#color/white"
android:singleLine="false"/>
<TextView
android:id="#+id/slideshow_description_anim2"
android:textSize="#dimen/description_font_size"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="2"
android:textColor="#color/white"
android:singleLine="false"/>
</TextSwitcher>
Here I add the transition animation to the TextSwitcher (in the adapter's getView method)
final TextSwitcher slideshowDescription = (TextSwitcher)slideshowView.findViewById(R.id.slideshow_description);
Animation outAnim = AnimationUtils.loadAnimation(context,
R.anim.slide_out_down);
Animation inAnim = AnimationUtils.loadAnimation(context,
R.anim.slide_in_up);
slideshowDescription.setInAnimation(inAnim);
slideshowDescription.setOutAnimation(outAnim);
Here is how I swap to the part of the description
private void updateScrollingDescription(SlideshowPhoto currentSlideshowPhoto, TextSwitcher switcherDescription){
String description = currentSlideshowPhoto.getDescription();
TextView descriptionView = ((TextView)switcherDescription.getCurrentView());
//note currentDescription may contain more text that is shown (but is always a substring
String currentDescription = descriptionView.getText().toString();
if(currentDescription == null || description==null){
return;
}
int indexEndCurrentDescription= descriptionView.getLayout().getLineEnd(1);
//if we are not displaying all characters, let swap to the not displayed substring
if(indexEndCurrentDescription>0 && indexEndCurrentDescription<currentDescription.length()){
String newDescription = currentDescription.substring(indexEndCurrentDescription);
switcherDescription.setText(newDescription);
}else if(indexEndCurrentDescription>=currentDescription.length() && indexEndCurrentDescription<description.length()){
//if we are displaying the last of the text, but the text has multiple sections. Display the first one again
switcherDescription.setText(description);
}else {
//do nothing (ie. leave the text)
}
}
And finally, here is where I setup the Timer which causes it to update every 3.5 seconds
public void setUpScrollingOfDescription(){
final CustomGallery gallery = (CustomGallery) findViewById(R.id.gallery);
//use the same timer. Cancel if running
if(timerDescriptionScrolling!=null){
timerDescriptionScrolling.cancel();
}
timerDescriptionScrolling = new Timer("TextScrolling");
final Activity activity = this;
long msBetweenSwaps=3500;
//schedule this to
timerDescriptionScrolling.scheduleAtFixedRate(
new TimerTask() {
int i=0;
public void run() {
activity.runOnUiThread(new Runnable() {
public void run() {
SlideshowPhoto currentSlideshowPhoto = (SlideshowPhoto)imageAdapter.getItem(gallery.getSelectedItemPosition());
View currentRootView = gallery.getSelectedView();
TextSwitcher switcherDescription = (TextSwitcher)currentRootView.findViewById(R.id.slideshow_description);
updateScrollingDescription(currentSlideshowPhoto,switcherDescription);
//this is the max times we will swap (to make sure we don't create an infinite timer by mistake
if(i>30){
timerDescriptionScrolling.cancel();
}
i++;
}
});
}
}, msBetweenSwaps, msBetweenSwaps);
}
Finally I can put this problem to a rest :)

Removing the extra padding in a GridView in android

I want to remove the extra padding that appears in a grid view. I have images of the size 128*128 which will be occupying cells in the grid. But somehow there is an extra space that gets added to the contents of the grid.
After some research, I was able to determine that I have to override the listSelector property of the grid view. Now here's my question - I know I have to specify something like an xml drawable here, but what to specify in that?? I tried using a shape drawable with padding and stroke set to 0dp to no avail.
The question is asked and answered here, but they haven't given what the drawable must contain.
Can some one help me with this. Thanks!
EDIT: Ok - here's a copy of the UI that I have. And the XML layout for the same is as follows:
<GridView android:id="#+id/GV_A2ZMenu" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:numColumns="4"
android:layout_gravity="top" android:stretchMode="columnWidth"
android:gravity="center" android:listSelector="#null" />
And I am using a BaseAdapter class to populate the gridView. Here's its code:
public class AtoZMenu extends BaseAdapter {
private static Context AppC;
private Integer[] MenuImg = { R.drawable.alphabet_a, R.drawable.alphabet_b,
R.drawable.alphabet_c, R.drawable.alphabet_d,
R.drawable.alphabet_e, R.drawable.alphabet_f,
R.drawable.alphabet_g, R.drawable.alphabet_h,
R.drawable.alphabet_i, R.drawable.alphabet_j,
R.drawable.alphabet_k, R.drawable.alphabet_l,
R.drawable.alphabet_m, R.drawable.alphabet_n,
R.drawable.alphabet_o, R.drawable.alphabet_p,
R.drawable.alphabet_q, R.drawable.alphabet_r,
R.drawable.alphabet_s, R.drawable.alphabet_t,
R.drawable.alphabet_u, R.drawable.alphabet_v,
R.drawable.alphabet_w, R.drawable.alphabet_x,
R.drawable.alphabet_y, R.drawable.alphabet_z };
public AtoZMenu(Context C) {
AppC = C;
}
public int getCount() {
return MenuImg.length;
}
public Object getItem(int position) {
return null;
}
public long getItemId(int position) {
return 0;
}
public View getView(int position, View convertView, ViewGroup parent) {
ImageView IV;
float density = AppC.getResources().getDisplayMetrics().density;
if (convertView == null) {
IV = new ImageView(AppC);
IV.setMaxHeight((int) (1));
} else {
IV = (ImageView) convertView;
}
IV.setImageResource(MenuImg[position]);
return IV;
}
}
Can you spot the mistake?
Note: In the end I ended up implementing a similar screen in a table layout which renders much better grids.
Yep, I've had the same problem. You want to set the listSelector to #null:
<!-- Setting the listSelector to null removes the 5px border -->
<GridView
android:id="#+id/view"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:listSelector="#null" />
Also, try the following:
myGridView.setStretchMode(GridView.STRETCH_COLUMN_WIDTH);
I see you can do this in the XML, but I didn't when I had this same problem; not sure why.
I also hard-coded the key height:
float density = getContext().getResources().getDisplayMetrics().density;
mKeyHeight = (int) (56 * density);
....
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageButton b = (ImageButton) convertView;
if (b == null) {
b = new ImageButton(getContext());
b.setMinimumHeight(mKeyHeight);
b.setBackgroundResource(R.drawable.btn_keyboard_key);
b.setOnClickListener(this);
}
}
Sorry about not giving a precise answer, so let me know if you still need help after that.
The correct answer is to set android:listSelector to #android:color/transparent, as user mvds said here.
I used a variation of Shawn's solution.. it looks nice on the Emulator.
1) Decide on the # of columns, I chose 4
2) Set the Column Width
float xdpi = this.getResources().getDisplayMetrics().xdpi;
int mKeyHeight = (int) ( xdpi/4 );
GridView gridView = (GridView) findViewById(R.id.gridview);
gridView.setColumnWidth( mKeyHeight );// same Height & Width
3) Setup the image in your adapter's getView method
imageView = new ImageView( mContext );
// (xdpi-4) is for internal padding
imageView.setLayoutParams(new GridView.LayoutParams( (int) (xdpi-4)/2, (int) (xdpi-4)/2));
imageView.setScaleType( ImageView.ScaleType.CENTER_CROP );
imageView.setPadding(1, 1, 1, 1);
4) Layout
<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/gridview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:numColumns="4"
android:verticalSpacing="0dp"
android:horizontalSpacing="0dp"
android:gravity="center"
android:listSelector="#null"
/>
<!--
android:columnWidth="90dp" Specified in code
android:stretchMode="columnWidth" no noticable change
-->
That's it.
Even I had the same problem.
Try this:
image.setLayoutParams(new GridView.LayoutParams(imageWidth , imageHeight));
imageView.setScaleType(ImageView.ScaleType.FIT_XY);.
Add padding accordingly for the images.It worked for me.
I had a similar problem, though in my case there was a quite large padding area at the bottom of my GridView (it was filled with the background color).
I haven't seen the solution to my issue here, so I'll post it here in case it's helpful.
Besides setting:
android:listSelector="#null"
in my GridView, I also had to set:
android:fadingEdgeLength="0px"
Or, in Java:
GridView.setFadingEdgeLength(0);
Try to give padding in pixels like this
android:paddingLeft="5px"

Horizontal ListView in Android?

Is it possible to make the ListView horizontally? I have done this using a gallery view, but the selected item comes to the center of the screen automatically. I don't want the selected item at the same spot I clicked. How can I rectify this problem? My idea was to set the ListView with a horizontal scroll. Share your idea?
As per Android Documentation RecyclerView is the new way to organize the items in listview and to be displayed horizontally
Advantages:
Since by using Recyclerview Adapter, ViewHolder pattern is
automatically implemented
Animation is easy to perform
Many more features
More Information about RecyclerView:
grokkingandroid.com
antonioleiva.com
Sample:
survivingwithandroid.com
Just add the below block to make the ListView to horizontal from vertical
Code-snippet
LinearLayoutManager layoutManager= new LinearLayoutManager(this,LinearLayoutManager.HORIZONTAL, false);
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mRecyclerView.setLayoutManager(layoutManager);
Paul doesn't bother to fix bugs of his library or accept users fixes. That's why I am suggesting another library which has similar functionality:
https://github.com/sephiroth74/HorizontalVariableListView
Update: on Jul 24, 2013 author (sephiroth74) released completely rewritten version based on code of android 4.2.2 ListView. I must say that it doesn't have all the errors which previous version had and works great!
#Paul answer links to a great solution, but the code doesn't allow to use onClickListeners on items children (the callback functions are never called). I've been struggling for a while to find a solution and I've decided to post here what you need to modify in that code (in case somebody need it).
Instead of overriding dispatchTouchEvent override onTouchEvent. Use the same code of dispatchTouchEvent and delete the method (you can read the difference between the two here http://developer.android.com/guide/topics/ui/ui-events.html#EventHandlers )
#Override
public boolean onTouchEvent(MotionEvent event) {
boolean handled = mGesture.onTouchEvent(event);
return handled;
}
Then, add the following code which will decide to steal the event from the item children and give it to our onTouchEvent, or let it be handled by them.
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch( ev.getActionMasked() ){
case MotionEvent.ACTION_DOWN:
mInitialX = ev.getX();
mInitialY = ev.getY();
return false;
case MotionEvent.ACTION_MOVE:
float deltaX = Math.abs(ev.getX() - mInitialX);
float deltaY = Math.abs(ev.getY() - mInitialY);
return ( deltaX > 5 || deltaY > 5 );
default:
return super.onInterceptTouchEvent(ev);
}
}
Finally, don't forget to declare the variables in your class:
private float mInitialX;
private float mInitialY;
Since Google introduced Android Support Library v7 21.0.0, you can use RecyclerView to scroll items horizontally. The RecyclerView widget is a more advanced and flexible version of ListView.
To use RecyclerView, just add dependency:
com.android.support:recyclerview-v7:23.0.1
Here is a sample:
public class MyActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_activity);
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
recyclerView.setLayoutManager(layoutManager);
MyAdapter adapter = new MyAdapter(myDataset);
recyclerView.setAdapter(adapter);
}
}
More info about RecyclerView:
https://developer.android.com/training/material/lists-cards.html
https://developer.android.com/reference/android/support/v7/widget/RecyclerView.html
This is a little (very) late, but I'm posting this in case someone comes by this later.
The Support Library as of the Android L preview has a RecyclerView that does exactly what you want.
Right now, you can only get it through the L preview SDK and you need to set your minSdk to L. But you can copy all of the necessary files into your project and use them that way until L is officially out.
You can download the preview docs here.
Warning: The API for Recycler View may change and it may have bugs.
Updated
The source code for horizontal listview is:
LinearLayoutManager layoutManager
= new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
RecyclerView myList = findViewById(R.id.my_recycler_view);
myList.setLayoutManager(layoutManager);
Download the jar file from here
now put it into your libs folder, right click it and select 'Add as library'
now in main.xml put this code
<com.devsmart.android.ui.HorizontalListView
android:id="#+id/hlistview"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
now in Activity class if you want Horizontal Listview with images then put this code
HorizontalListView hListView = (HorizontalListView) findViewById(R.id.hlistview);
hListView.setAdapter(new HAdapter(this));
private class HAdapter extends BaseAdapter {
LayoutInflater inflater;
public HAdapter(Context context) {
inflater = LayoutInflater.from(context);
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return Const.template.length;
}
#Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return position;
}
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
HViewHolder holder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.listinflate, null);
holder = new HViewHolder();
convertView.setTag(holder);
} else {
holder = (HViewHolder) convertView.getTag();
}
holder.img = (ImageView) convertView.findViewById(R.id.image);
holder.img.setImageResource(Const.template[position]);
return convertView;
}
}
class HViewHolder {
ImageView img;
}
Its actually very simple:
simply Rotate the list view to lay on its side
mlistView.setRotation(-90);
Then upon inflating the children, that should be inside the getView method. you rotate the children to stand up straight:
mylistViewchild.setRotation(90);
Edit:
if your ListView doesnt fit properly after rotation, place the ListView inside this RotateLayout like this:
<com.github.rongi.rotate_layout.layout.RotateLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:angle="90"> <!-- Specify rotate angle here -->
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>
</com.github.rongi.rotate_layout.layout.RotateLayout>
My solution is to simply use ViewPager widget. It isn't center-locked as Gallery and has a built-in features for recycling views (as ListView). You may see similar approach at Google Play app, whenever you deal with horizontally scrollable lists.
You just need to extend PagerAdapter and perform a couple of tweaks there:
public class MyPagerAdapter extends PagerAdapter {
private Context mContext;
public MyPagerAdapter(Context context) {
this.mContext = context;
}
// As per docs, you may use views as key objects directly
// if they aren't too complex
#Override
public Object instantiateItem(ViewGroup container, int position) {
LayoutInflater inflater = LayoutInflater.from(mContext);
View view = inflater.inflate(R.layout.item, null);
container.addView(view);
return view;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
#Override
public int getCount() {
return 10;
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
// Important: page takes all available width by default,
// so let's override this method to fit 5 pages within single screen
#Override
public float getPageWidth(int position) {
return 0.2f;
}
}
As result, you'll have horizontally scrollable widget with adapter, like this:
Note: Android now supports horizontal list views using RecyclerView, so now this answer is deprecated, for information about RecyclerView :
https://developer.android.com/reference/android/support/v7/widget/RecyclerView
I have developed a logic to do it without using any external horizontal scrollview library, here is the horizontal view that I achieved and I have posted my answer here:https://stackoverflow.com/a/33301582/5479863
My json response is this:
{"searchInfo":{"status":"1","message":"Success","clist":[{"id":"1de57434-795e-49ac-0ca3-5614dacecbd4","name":"Theater","image_url":"http://52.25.198.71/miisecretory/category_images/movie.png"},{"id":"62fe1c92-2192-2ebb-7e92-5614dacad69b","name":"CNG","image_url":"http://52.25.198.71/miisecretory/category_images/cng.png"},{"id":"8060094c-df4f-5290-7983-5614dad31677","name":"Wine-shop","image_url":"http://52.25.198.71/miisecretory/category_images/beer.png"},{"id":"888a90c4-a6b0-c2e2-6b3c-561788e973f6","name":"Chemist","image_url":"http://52.25.198.71/miisecretory/category_images/chemist.png"},{"id":"a39b4ec1-943f-b800-a671-561789a57871","name":"Food","image_url":"http://52.25.198.71/miisecretory/category_images/food.png"},{"id":"c644cc53-2fce-8cbe-0715-5614da9c765f","name":"College","image_url":"http://52.25.198.71/miisecretory/category_images/college.png"},{"id":"c71e8757-072b-1bf4-5b25-5614d980ef15","name":"Hospital","image_url":"http://52.25.198.71/miisecretory/category_images/hospital.png"},{"id":"db835491-d1d2-5467-a1a1-5614d9963c94","name":"Petrol-Pumps","image_url":"http://52.25.198.71/miisecretory/category_images/petrol.png"},{"id":"f13100ca-4052-c0f4-863a-5614d9631afb","name":"ATM","image_url":"http://52.25.198.71/miisecretory/category_images/atm.png"}]}}
Layout file :
<?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"
android:weightSum="5">
<fragment
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="4" />
<HorizontalScrollView
android:id="#+id/horizontalScroll"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<LinearLayout
android:id="#+id/ll"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="horizontal">
</LinearLayout>
</HorizontalScrollView>
</LinearLayout>
class file:
LinearLayout linearLayout = (LinearLayout) findViewById(R.id.ll);
for (int v = 0; v < collectionInfo.size(); v++) {
/*---------------Creating frame layout----------------------*/
FrameLayout frameLayout = new FrameLayout(ActivityMap.this);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, getPixelsToDP(90));
layoutParams.rightMargin = getPixelsToDP(10);
frameLayout.setLayoutParams(layoutParams);
/*--------------end of frame layout----------------------------*/
/*---------------Creating image view----------------------*/
final ImageView imgView = new ImageView(ActivityMap.this); //create imageview dynamically
LinearLayout.LayoutParams lpImage = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
imgView.setImageBitmap(collectionInfo.get(v).getCatImage());
imgView.setLayoutParams(lpImage);
// setting ID to retrieve at later time (same as its position)
imgView.setId(v);
imgView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// getting id which is same as its position
Log.i(TAG, "Clicked on " + collectionInfo.get(v.getId()).getCatName());
// getting selected category's data list
new GetSelectedCategoryData().execute(collectionInfo.get(v.getId()).getCatID());
}
});
/*--------------end of image view----------------------------*/
/*---------------Creating Text view----------------------*/
TextView textView = new TextView(ActivityMap.this);//create textview dynamically
textView.setText(collectionInfo.get(v).getCatName());
FrameLayout.LayoutParams lpText = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.BOTTOM | Gravity.CENTER);
// Note: LinearLayout.LayoutParams 's gravity was not working so I putted Framelayout as 3 paramater is gravity itself
textView.setTextColor(Color.parseColor("#43A047"));
textView.setLayoutParams(lpText);
/*--------------end of Text view----------------------------*/
//Adding views at appropriate places
frameLayout.addView(imgView);
frameLayout.addView(textView);
linearLayout.addView(frameLayout);
}
private int getPixelsToDP(int dp) {
float scale = getResources().getDisplayMetrics().density;
int pixels = (int) (dp * scale + 0.5f);
return pixels;
}
trick that is working here is the id that I have assigned to ImageView "imgView.setId(v)" and after that applying onClickListener to that I am again fetching the id of the view....I have also commented inside the code so that its easy to understand,
I hope this may be very useful...
Happy Coding... :)
This isn't much of an answer, but how about using a Horizontal Scroll View?
You can use RecyclerView in the support library. RecyclerView is a generalized version of ListView that supports:
A layout manager for positioning items
Default animations for common
item operations
Android Recycler View Docs
I've done a lot of searching for a solution to this problem. The short answer is, there is no good solution, without overriding private methods and that sort of thing. The best thing I found was to implement it myself from scratch by extending AdapterView. It's pretty miserable. See my SO question about horizontal ListViews.
I had to do the same for one of my projects and I ended up writing my own as well. I called it HorzListView is now part of my open source Aniqroid library.
http://aniqroid.sileria.com/doc/api/ (Look for downloads at the bottom or use google code project to see more download options: http://code.google.com/p/aniqroid/downloads/list)
The class documentation is here: http://aniqroid.sileria.com/doc/api/com/sileria/android/view/HorzListView.html
For my application, I use a HorizontalScrollView containing LinearLayout inside, which has orientation set to horizontal. In order to add images inside, I create ImageViews inside the activity and add them to my LinearLayout. For example:
<HorizontalScrollView
android:id="#+id/photo_scroll"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
android:scrollbars="horizontal"
android:visibility="gone">
<LinearLayout
android:id="#+id/imageview_holder"
android:layout_width="wrap_content"
android:orientation="horizontal"
android:layout_height="match_parent">
</LinearLayout>
</HorizontalScrollView>
An this works perfectly fine for me. In the activity all I have to do is something like the code below:
LinearLayout imgViewHolder = findViewById(R.id.imageview_holder);
ImageView img1 = new ImageView(getApplicationContext());
//set bitmap
//set img1 layout params
imgViewHolder.add(img1);
ImageView img2 = new ImageView(getApplicationContext());
//set bitmap
//set img2 layout params
imgViewHolder.add(img2);
As I said that works for me, and I hope it helps somebody looking to achieve this as well.
well you can always create your textviews etc dynamically and set your onclicklisteners like you would do with an adapter
HorizontialListView can't work when the data in the adapter is involved in another thread. Everything runs 100% on UI thread.This is a big problem in multithread. I think using HorizontialListView is not the best solution for your problem.HorzListView is a better way.You just replace your previous Gallery with HorzListView.You neednot modify the code about the adapter.Then everything goes the way you hope.See https://stackoverflow.com/a/12339708/1525777 about HorzListView.
I had used horizontal listview link in my project & I got good results. I had been used devsmart library initially but it gave me some issues. So best way to use horizontal listview link as it recovered my issues & also I recently launched my app on Google PlayStore using this library & got nice response from users. So I recommend you to use the same library which I mentioned above to show listview horizontally. Enjoy :)
There is a great library for that, called TwoWayView, it's very easy to implement, just include the project library into your work space and add it as a library project to your original project, and then follow the following steps which are originally mentioned here:
First, let's add a style indicating the orientation of the ListView
(horizontal or vertical) in (res/values/styles.xml):
<style name="TwoWayView">
<item name="android:orientation">horizontal</item>
</style>
Then,
In your Layout XML, use the following code to add the TwoWayView:
<org.lucasr.twowayview.TwoWayView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/lvItems"
style="#style/TwoWayView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:drawSelectorOnTop="false"
tools:context=".MainActivity" />
and finally, just declare it and deal with it like any regular ListView:
TwoWayView lvTest = (TwoWayView) findViewById(R.id.lvItems);
All the methods of ListView will work here as usual, but there is only one difference I noticed, which is when setting the choice mode, the method setChoiceMode not takes an int value but a value from enum called ChoiceMode, so list_view.setChoiceMode(ListView.CHOICE_MODE_SINGLE); will be lvTest.setChoiceMode(ChoiceMode.SINGLE); // or MULTIPLE or NONE.
You may use ViewFlipper to include the layout XML and add images , listview for each layout XML

Categories

Resources