可以ListView
横着做吗?我已经使用图库视图完成了此操作,但所选项目会自动出现在屏幕中央。我不希望所选项目位于我单击的同一位置。我该如何解决这个问题?我的想法是设置ListView
水平滚动。分享你的想法?
19 回答
根据 Android 文档RecyclerView
是在列表视图中组织项目并水平显示的新方法
好处:
- 由于通过使用 Recyclerview Adapter,ViewHolder 模式是自动实现的
- 动画很容易执行
- 更多功能
更多信息RecyclerView
:
样本:
只需添加以下块即可使ListView
水平从垂直
代码片段
LinearLayoutManager layoutManager= new LinearLayoutManager(this,LinearLayoutManager.HORIZONTAL, false);
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mRecyclerView.setLayoutManager(layoutManager);
Paul 不会费心修复他的库的错误或接受用户修复。这就是为什么我建议另一个具有类似功能的库:
https://github.com/sephiroth74/HorizontalVariableListView
更新:2013 年 7 月 24 日,作者 (sephiroth74) 发布了基于 android 4.2.2 ListView 代码完全重写的版本。我必须说它没有以前版本的所有错误并且效果很好!
@Paul 回答链接到一个很好的解决方案,但代码不允许在子项上使用onClickListeners(永远不会调用回调函数)。我一直在努力寻找解决方案,我决定在这里发布您需要在该代码中修改的内容(以防有人需要)。
而不是覆盖dispatchTouchEvent
override onTouchEvent
。使用相同的代码dispatchTouchEvent
并删除方法(您可以在此处阅读两者的区别http://developer.android.com/guide/topics/ui/ui-events.html#EventHandlers)
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean handled = mGesture.onTouchEvent(event);
return handled;
}
然后,添加以下代码,该代码将决定从项子项中窃取事件并将其提供给我们的onTouchEvent
,或者由他们处理。
@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);
}
}
最后,不要忘记在你的类中声明变量:
private float mInitialX;
private float mInitialY;
由于 Google 推出了 Android Support Library v7 21.0.0,您可以使用 RecyclerView 水平滚动项目。RecyclerView 小部件是 ListView 的更高级和灵活的版本。
要使用 RecyclerView,只需添加依赖项:
com.android.support:recyclerview-v7:23.0.1
这是一个示例:
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);
}
}
有关 RecyclerView 的更多信息:
这有点(非常)晚了,但我会发布这个,以防以后有人来。
Android L 预览版中的支持库可以满足RecyclerView
您的需求。
目前,您只能通过 L 预览版 SDK 获取它,并且需要将您的设置minSdk
为L
. 但是您可以将所有必要的文件复制到您的项目中并以这种方式使用它们,直到 L 正式推出。
您可以在此处下载预览文档。
警告:Recycler View 的 API 可能会更改并且可能存在错误。
更新
水平列表视图的源代码是:
LinearLayoutManager layoutManager
= new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
RecyclerView myList = findViewById(R.id.my_recycler_view);
myList.setLayoutManager(layoutManager);
从这里下载 jar 文件
现在将其放入您的 libs 文件夹,右键单击它并选择“添加为库”
现在在 main.xml 中放置这段代码
<com.devsmart.android.ui.HorizontalListView
android:id="@+id/hlistview"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
现在在 Activity 类中,如果您想要带图像的水平列表视图,然后输入此代码
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;
}
它实际上非常简单:只需将列表视图旋转到其一侧
mlistView.setRotation(-90);
然后在给孩子充气时,应该在 getView 方法内。你旋转孩子们站直:
mylistViewchild.setRotation(90);
编辑: 如果您的 ListView 在旋转后不适合,请将 ListView 放置在此RotateLayout 中,如下所示:
<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>
我的解决方案是简单地使用ViewPager
小部件。它不是中心锁定的 as并且具有用于回收视图 (as )Gallery
的内置功能。ListView
每当您处理水平滚动列表时,您可能会在 Google Play 应用程序中看到类似的方法。
您只需要在那里扩展PagerAdapter
并执行一些调整:
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;
}
}
结果,您将拥有带有适配器的水平可滚动小部件,如下所示:
注意:Android 现在支持使用 RecyclerView 的水平列表视图,所以现在这个答案已被弃用,有关 RecyclerView 的信息: https ://developer.android.com/reference/android/support/v7/widget/RecyclerView
我已经开发了一个逻辑来做到这一点,而不使用任何外部水平滚动视图库,这是我实现的水平视图,我在这里发布了我的答案:https ://stackoverflow.com/a/33301582/5479863
我的 json 响应是这样的:
{"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"}]}}
布局文件:
<?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>
类文件:
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;
}
在这里工作的技巧是我分配给 ImageView “imgView.setId(v)” 的 id,然后将 onClickListener 应用到该 id 上,我再次获取视图的 id....我还在代码中评论了所以它易于理解,我希望这可能非常有用......快乐编码...... :)
这不是一个很好的答案,但是使用Horizontal Scroll View怎么样?
您可以在支持库中使用 RecyclerView。RecyclerView 是 ListView 的通用版本,它支持:
- 用于定位项目的布局管理器
- 常见项目操作的默认动画
我已经做了很多寻找解决这个问题的方法。简短的回答是,如果不覆盖私有方法之类的东西,就没有好的解决方案。我发现的最好的事情是通过扩展自己从头开始实现它AdapterView
。真是太惨了。请参阅我关于水平 ListViews 的 SO 问题。
我必须为我的一个项目做同样的事情,最后我也写了自己的。我称它为HorzListView现在是我的开源Aniqroid库的一部分。
http://aniqroid.sileria.com/doc/api/ (在底部查找下载或使用谷歌代码项目查看更多下载选项:http ://code.google.com/p/aniqroid/downloads/list )
类文档在这里:http ://aniqroid.sileria.com/doc/api/com/sileria/android/view/HorzListView.html
对于我的应用程序,我使用了一个包含 LinearLayout 的 HorizontalScrollView,它的方向设置为水平。为了在里面添加图像,我在 Activity 中创建 ImageViews 并将它们添加到我的 LinearLayout 中。例如:
<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>
这对我来说非常好。在活动中,我所要做的就是如下代码:
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);
正如我所说,这对我有用,我希望它也能帮助那些希望实现这一目标的人。
好吧,您始终可以动态创建文本视图等,并像使用适配器一样设置 onclicklisteners
当适配器中的数据涉及到另一个线程时,HorizontialListView 无法工作。一切都在 UI 线程上运行 100%。这是多线程中的一个大问题。我认为使用HorizontalListView并不是解决您问题的最佳解决方案。HorzListView是一种更好的方法。您只需用HorzListView替换以前的Gallery即可。您无需修改有关适配器的代码。然后一切都按您希望的方式进行。请参阅https:// stackoverflow.com/a/12339708/1525777关于 HorzListView。
有一个很棒的库,叫做TwoWayView,它很容易实现,只需将项目库包含到您的工作空间中并将其作为库项目添加到您的原始项目中,然后按照最初提到的以下步骤操作:
首先,让我们在 (res/values/styles.xml) 中添加一个样式,指示 ListView 的方向(水平或垂直):
<style name="TwoWayView">
<item name="android:orientation">horizontal</item>
</style>
然后,
在您的布局 XML 中,使用以下代码添加 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" />
最后,只需声明它并像任何常规一样处理它ListView
:
TwoWayView lvTest = (TwoWayView) findViewById(R.id.lvItems);
的所有方法都ListView
将照常在这里工作,但我注意到只有一个区别,即在设置选择模式时,该方法setChoiceMode
不接受int
值,而是从enum
被调用的值ChoiceMode
,所以list_view.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
将是lvTest.setChoiceMode(ChoiceMode.SINGLE); // or MULTIPLE or NONE
。
您可以使用 ViewFlipper 来包含布局 XML 并为每个布局 XML 添加图像、列表视图