Horizontal ListView in Android? - 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

Related

Scrollbar on Top Side in Horizontal RecyclerView

I am working on the Simple demo of Horizontal RecyclerView.
I want to display scrollbar along with the recyclerview. So I have added android:scrollbars="horizontal" and android:scrollbarSize="5dp" in XML.
I am able to get the Scrollbar but it is showing on the bottom. What I want to achieve is to show it on Top. I have found some questions like this but none of them are for horizontal recyclerView + top side scrollbar.
Here is the code which I have tried so far:
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:isScrollContainer="false"
android:orientation="horizontal"
android:scrollbars="horizontal"
android:scrollbarSize="5dp"
android:visibility="visible" />
Thanks!
I have searched couple of hours but not found anything as per your requirement. But there are some trikes or do with some hacky code we can get output as per your requirement.
Set your RecyclerView as below in your xml file.
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbarAlwaysDrawHorizontalTrack="true"
android:scrollbarSize="10dp"
android:scrollbarStyle="outsideInset"
android:scrollbarThumbVertical="#color/black"
android:scrollbars="horizontal"
android:verticalScrollbarPosition="right"/>
Put your data in revers order in your List or ArrayList because we need to rotate the recyclerviews so when we rotate it then our data will be display as an ASEC order.
//call this method for set recyclerview
private void setRecyclerView()
{
//Please make sure with your item that it will be inserted in revers order then an then it will be working
ArrayList<String> itemList = new ArrayList<>();
for (int i = 50; i > 0; i--){
itemList.add("item " + i);
}
ContainerAdapter adapterMessage = new ContainerAdapter(MainActivity.this, itemList);
if (adapterMessage != null)
{
rvItemList.setHasFixedSize(true);
rvItemList.setLayoutManager(new LinearLayoutManager(MainActivity.this,
LinearLayoutManager.HORIZONTAL, false);
rvItemList.setItemAnimator(new DefaultItemAnimator());
rvItemList.setAdapter(adapterMessage);
//here is the main line for your requirement
rvItemList.setRotation(180);
adapterMessage.notifyDataSetChanged();
}
Now last, In your adapter please rotate your all view in revers direction like below.
public class ViewHolder extends RecyclerView.ViewHolder
{
TextView txt_name;
public ViewHolder(View itemView) {
super(itemView);
txt_name = (TextView) itemView.findViewById(R.id.txt_name);
// here you need to revers rotate your view because your recyclerview is already rotate it so your view is also rotated and you need to revers rotate that view
txt_name.setRotation(-180);
}
}
If you do code as above then your item and its output look like this OutPut
Please make sure to doing this kind of code because android will not responsible for this kind of code, but as per your requirement you can do like this.

Espresso: How do I scroll to an item in a HorizontalScrollView by index?

This is what my HorizontalScrollView looks like:
<HorizontalScrollView
android:layout_below="#id/saved_circuits_title"
android:id="#+id/saved_circuits_scrollview"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<LinearLayout
android:id="#+id/saved_circuits_scroll"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:orientation="horizontal">
</LinearLayout>
</HorizontalScrollView>
In my HomeActivity I have the following relevant code that populates the HorizontalScrollView with bitmaps
onCreate{
...
this.savedCircuitsScroll = (LinearLayout) findViewById(R.id.saved_circuits_scroll);
...
}
updateSavedCircuits(){
...// code to make an ImageView from a retrieved bitmap
newImageImage.setOnClickListener(this.thumbnailListener);
this.savedCircuitsScroll.addView(newImageImage);
...
}
How do I use Espresso to scroll to an ImageView at a specified index in my HorizontalScrollView and click it?
What I've tried
I do not have ID's in my layout xml so an approach such as this does not work:
onView( withId( R.id.button)).perform( scrollTo(), click());
I know you can click on an item by index in a RecyclerView and tried finding an analogous approach for HorizontalScrollViews:
onView(withId(R.id.saved_circuits_scroll))
.perform(HorizontalScrollViewActions.actionOnItemAtPosition(0, click()));
Except HorizontalScrollViewActions does not exist.
or following this blog I tried the following to at least click an item in the HorizontalScrollView at a specified index:
// Click item at position 3
onView(withHorizontalScrollView(R.id.scroll_view).atPosition(3)).perform(click());
// Convenience helper
public static HorizontalScrollViewMatcher withHorizontalScrollView(final int horizontalScrollViewId) {
return new HorizontalScrollViewMatcher(horizontalScrollId);
}
except HorizontalScrollViewMatcher does not exist.
What do we do for HorizontalScrollView? It isn't a descendant of ScrollView so the answer here suggests I need to implement my own custom ViewAction. All I want to do is scroll to an item in a HorizontalScrollView by index and click it. Is this really needed? If this is what I need to do, how do I go about implementing this custom ViewAction?
In my case I got it by using:
onView(allOf(withId(R.id.itemTextView), withEffectiveVisibility(Visibility.VISIBLE), withText(R.string.categories))).perform(scrollTo(), click())
R.id.itemTextView is a TextView (with text R.string.categories) added dynamically to the LinearLayout:
<HorizontalScrollView>
<LinearLayout>
... [child added dynamically]
</LinearLayout>
</HorizontalScrollView>
Try to add this matcher.
public static Matcher<View> withIdAndParentId(final int viewId, final int parentId) {
Assert.assertTrue(viewId != -1);
Assert.assertTrue(parentId != -1);
return new TypeSafeMatcher<View>() {
#Override
public void describeTo(Description description) {
}
#Override
public boolean matchesSafely(View view) {
return view.getId() == viewId && isThereParentWithIdInHierarchy(view);
}
private boolean isThereParentWithIdInHierarchy(View view) {
ViewParent viewParent = view.getParent();
if (viewParent == null || !(viewParent instanceof ViewGroup))
return false;
ViewGroup parent = (ViewGroup) viewParent;
return parent.getId() == parentId || isThereParentWithIdInHierarchy(parent);
}
};
}
This is the way to use it :
onView(withIdAndParentId(R.id.YOUR_PARTICULAR_VIEW_ID, R.id.horizontalScrollViewId)).perform(scrollTo(), click());
Hope, it helps.
OK so in my particular case I found out that my scroll views had no ID associated with them (or none that I could reach reasonably, hence I couldn't use Mody's answer). However, they did have a tag associated with them so I could use Espresso's withTagValue ViewMatcher instead. Each view was associated with a circuitProject object (of course for you it may be different). And I have access to the following:
ArrayList<CircuitProject> circuitProjects = new ArrayList<>();
The index of a circuitProject object happens to be the position of the associated view in the HorizontalScrollView. The tag is the folder the circuitProject object is saved to. From here it is straightforward to get the behaviour I need with Espresso scrolling to a particular index in the HorizontalScrollView:
onView(withTagValue(withStringMatching(circuitProject.getFolderID()))).perform(scrollTo(), click());

Using both a CardScrollView and a ScrollView

I have a CardScrollView with multiple cards. Swiping left and right moves between the cards.
Some of the cards have a lot of content on them. I used a ScrollView so the user can scroll through the card to see the content.
Glass doesn't know whether it should scroll to a different card or scroll on the card it is on when the user swipes their finger for obvious reasons. It chooses to scroll to a different card.
To differentiate, I want to use the GestureDetector to make a one finger scroll scroll cards, and a two finger scroll scroll on the selected card. Seems easy enough, so I made the createGestureDetector() method and put if statements for each case.
Now I have a problem...I do not know how to tell the CardScrollView to advance or go back a card, and I dont know how to make the ScrollBody scroll based on the gesture.
I looked through all of the available methods and nothing stuck out to me as particularly helpful. Does anyone have any idea how to do this?
Bonus question: I saw a lot of "dispatch" commands, like dispatchGenericMotionEvent. What do dispatch methods do?
EDIT:
Here is my code after Jean Vacca's suggestion:
private GestureDetector createGestureDetector(Context context) {
GestureDetector gestureDetector = new GestureDetector(context);
gestureDetector.setFingerListener(new GestureDetector.FingerListener() {
#Override
public void onFingerCountChanged(int previousCount, int currentCount) {
if(currentCount == 2){
mCardScrollView.deactivate();
}else{
mCardScrollView.activate();
}
}
});
return gestureDetector;
}
and the xml for my views is:
<?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="fill_parent" >
<ScrollView
android:id="#+id/scrollBody"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="false">
<LinearLayout
android:id="#+id/scrollLinearLayout"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
</LinearLayout>
</ScrollView>
</RelativeLayout>
Which is filled with TextViews in this code segment located in the CardScrollAdapter:
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
int nextID = 3;
if (convertView == null) {
convertView = View.inflate(context, R.layout.my_card, null);
holder = new ViewHolder();
MyClass mine = mMyList.get(position);
LinearLayout ll = (LinearLayout)convertView.findViewById(R.id.scrollLinearLayout);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
holder.name = new TextView(this.context);
holder.name.setId(nextID);
nextID++;
holder.name.setTextSize(50);
holder.name.setText(mine.getName());
holder.name.setLayoutParams(lp);
holder.name.setGravity(Gravity.CENTER);
ll.addView(holder.name);
holder.infoTextViews = new ArrayList<TextView>(mine.getInfo().size());
for(int i = 0; i < mine.getInfo().size(); i++)
{
holder.infoTextViews.add(new TextView(this.context));
TextView tv = holder.infoTextViews.get(i);
tv.setId(nextID);
nextID++;
tv.setTextSize(24);
tv.setText(mine.getInfo().get(i));
tv.setLayoutParams(lp);
tv.setGravity(Gravity.CENTER);
ll.addView(tv);
}
convertView.setTag(holder);
}
else {
holder = (ViewHolder) convertView.getTag();
}
return convertView;
}
I hope these edits help!
I had a similar problem on my project. To resolve it, I had to handle the "onFingerCountChanged" in the GestureDetector and desactivate the CardScrollView when i have 2 fingers count. So when I use one finger the cardscrollview scroll normaly and when I use two finger on can scroll in my card using the gestureDetector.
You code should look something like this :
gestureDetector.setFingerListener(new GestureDetector.FingerListener() {
#Override
public void onFingerCountChanged(int previousCount, int currentCount) {
if(currentCount == 2){
yourCardScrollView.deactivate();
}else{
yourCardScrollView.activate();
}
}
....
}
EDIT: I notice that my first answer is not work. I have another one.
You can use following code in your Activity.
#Override
public boolean dispatchGenericMotionEvent(MotionEvent ev) {
if (ev.getPointerCount() > 1) {
return true;
}
return super.dispatchGenericMotionEvent(ev);
}
When dispatchGenericMotionEvent actives, detect if pointer is greater than one (muit-touch), return true and consume it.
I tested, but still have bug.
https://code.google.com/p/google-glass-api/issues/detail?id=632
Reply me if it works.

How to put GridView inside ScrollView

I have to design layout such that whole layout should scroll and inside layout I have to display related content in Grid form so I decided to use GridView.But problem is that I’m unable to use GridView inside ScrollView I have read documentation(Documentation also saying that we should not use GridView inside ScrollView) also.But I have to do this,so can any please give me some idea about this.Thanks
There are definitely benefits to a GridView beside the inherent scrolling. For example, a consistent, dynamic layout of cells that will expand and contract based on the data you pass into it. So, when people say it's not good to desire such a functionality, I think that's wrong because you could want the dynamic grid of images (views) inside of a scrolling view, but want that entire scrolling view to contain other things than just the grid cells.
Now, here is how you can do this. Check the answer here. It is an expandable height GridView, which you will want to import / create in your project. What that basically means is that as more items are added to the GridView, it will just expand its height, as opposed to keeping its height set and using scrolling. This is exactly what you want.
Once you have the ExpandableHeightGridView in your project, go to your XML layout where you want the GridView to be. You can then do something like this (paraphrasing):
<ScrollView ...>
<RelativeLayout ...>
<com.example.ExpandableHeightGridView ... />
<other view items />
</RelativeLayout>
</ScrollView>
Then, in your activity where you set the GridView's adapter, you want to make sure you set it to expand. So:
ExpandableHeightGridView gridView = (ExpandableHeightGridView) findViewById(R.id.myId);
gridView.setAdapter(yourAdapter);
gridView.setExpanded(true);
The reason you want this expandable GridView is because, the fact that a standard GridView doesn't expand is what causes it to scroll. It sticks to a certain height, and then as more items fill it past its view bounds, it becomes scrollable. Now, with this, your GridView will always expand its height to fit the content within it, thus never allowing it to enter its scrolling mode. This enables you to use it inside of the ScrollView and use other view elements above or below it within the ScrollView, and have them all scroll.
This should give you the result you're looking for. Let me know if you have any questions.
I know I'm late but I have another solution which I must share and which works flawlessly. Here, the method calculates the GridView height based on the number of items it contains and sets the height to the GridView at run time.
public void setGridViewHeightBasedOnChildren(GridView gridView, int columns) {
ListAdapter listAdapter = gridView.getAdapter();
if (listAdapter == null) {
// pre-condition
return;
}
int totalHeight = 0;
int items = listAdapter.getCount();
int rows = 0;
View listItem = listAdapter.getView(0, null, gridView);
listItem.measure(0, 0);
totalHeight = listItem.getMeasuredHeight();
float x = 1;
if( items > columns ){
x = items/columns;
rows = (int) (x + 1);
totalHeight *= rows;
}
ViewGroup.LayoutParams params = gridView.getLayoutParams();
params.height = totalHeight;
gridView.setLayoutParams(params);
}
After you have called setAdapter on your gridview, just call
setGridViewHeightBasedOnChildren( <yourGridView> , <no of grid view columns> )
and it'll work.
You can the define the gridview in your xml as you normally do
and let the code take care of it. :)
I found a way to give the GridView a fixed size inside ScrollView, and enable scrolling it. That allows you to see the entire ScrollView without having to scroll all elements of the GridView, and it makes more sense to me that using an ExpandableHeightGridView.
To do so, you would have to implement a new class extending GridView and override onTouchEvent() to call requestDisallowInterceptTouchEvent(true).
Thus, the parent view will leave the Grid intercept touch events.
GridViewScrollable.java:
package com.example;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.GridView;
public class GridViewScrollable extends GridView {
public GridViewAdjuntos(Context context) {
super(context);
}
public GridViewAdjuntos(Context context, AttributeSet attrs) {
super(context, attrs);
}
public GridViewAdjuntos(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public boolean onTouchEvent(MotionEvent ev){
// Called when a child does not want this parent and its ancestors to intercept touch events.
requestDisallowInterceptTouchEvent(true);
return super.onTouchEvent(ev);
}
}
Add it in your layout with the characteristics and margins you want, inside a ScrollView:
<ScrollView 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:isScrollContainer="true" >
<com.example.GridViewScrollable
android:id="#+id/myGVS"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:numColumns="auto_fit"
android:stretchMode="columnWidth" />
</ScrollView>
And just get it in your activity:
GridViewScrollable myGridView = (GridViewScrollable) findViewById(R.id.myGVS);
I hope it helps =)
In Kotlin:
class GridViewScrollable #JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : GridView(context, attrs, defStyleAttr) {
override fun onTouchEvent(ev: MotionEvent?): Boolean {
// Called when a child does not want this parent and its ancestors to intercept touch events.
requestDisallowInterceptTouchEvent(true)
return super.onTouchEvent(ev)
}
}
There is an annoying warning: "Custom view GridViewScrollable overrides onTouchEvent but not performClick". Please, resolve yourself if you want.
I was also trying to make a GridView scrollable inside a NestedScrollView.
This answer on another question helped me: https://stackoverflow.com/a/38612612
Enable your GridView Property as
android:nestedScrollingEnabled="true"
Original poster: Droid_Dev
To use gridview inside scrollview, set scrollview android:fillViewport="true"
I know its late to answer here but may be useful to some new developers.
If you have used dennisdrew's answer and you have content above your grid and it gets hidden when you open your view simply add the last line below
ExpandableHeightGridView gridView = (ExpandableHeightGridView) findViewById(R.id.myId);
gridView.setAdapter(yourAdapter);
gridView.setExpanded(true);
gridView.setFocusable(false);
i would not force the issue. GridView does not work well in a scrollView. instead convert your gridview into a recyclerview and use a gridLayoutManager to resolve the issue.
It's better to use ExpandableHeightlistView or ExpandableHeightGridView inside scrollview.
Logic
Calculate entire height by providing a very large height hint. But do not use the highest 2 bits of this integer; those are reserved for the MeasureSpec mode.
int expandSpec = MeasureSpec.makeMeasureSpec(
Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
ViewGroup.LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
for further information explore the example below with demo
http://www.londatiga.net/it/programming/android/make-android-listview-gridview-expandable-inside-scrollview/
Trust this solution worked for me!
android:nestedScrollingEnabled="true"
The code above inside grid view enables to scroll gridview
and set width and height
android:layout_width="match_parent"
android:layout_height="200sp"
This will work even inside scrollview
Thanks for the previous answers I figured out this for the previous answers.
Thanks to them
gridView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
v.getParent().requestDisallowInterceptTouchEvent(true);
return false;
}
});
// Setting on Touch Listener for handling the touch inside ScrollView
If you want to have GridView inside ScrollView / RecyclerView, there are 2 cases:
If you want to have GridView with all rows visible, see https://stackoverflow.com/a/63724794/2914140.
If you want to have one row visible in GridView, but be able to scroll it (to reveal other rows), see https://stackoverflow.com/a/26852498/2914140.

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"

Categories

Resources