【问题标题】:Android - Horizontal Scrolling Views Inside Vertically Scrolling ViewAndroid - 垂直滚动视图内的水平滚动视图
【发布时间】:2013-07-18 09:55:25
【问题描述】:

在 Android 上,我想实现以下类型的缩略图滚动网格。

前两行水平滚动...并且,包括前两行在内的整个页面垂直滚动。

两个水平行都会在水平滚动时动态加载其他图像...此外,网格将在垂直滚动时动态加载。 (项目总数提前未知)

我关心的问题是:

  1. 水平滑动和垂直滑动可以很好地协同工作。
  2. 该视图回收将适用于所有滚动视图集。
  3. 即使有 8 行水平行,使得底部网格最初不可见,但仍可以垂直滚动。
  4. 您会为此屏幕的每个部分推荐哪种类型的视图(例如 ListView、ScrollView 等...)?
  5. 我可能需要处理哪些问题(例如,向上滑动到父视图等...)?

谢谢...刚刚开始我的 Android 编码冒险!


(来源:brianrice.com

【问题讨论】:

    标签: android android-listview horizontal-scrolling android-scrollview vertical-scrolling


    【解决方案1】:

    你的长篇故事的意思很简单: Vertical RecyclerView 中的水平 RecyclerView - 类似于新的 google play 布局

    按照这些步骤进行

    步骤:1

    创建两个模型类,如下所示。

    SingleItemModel.java

    package com.pratap.gplaystore.models;
    
    
    public class SingleItemModel {
    
    
        private String name;
        private String url;
        private String description;
    
    
        public SingleItemModel() {
        }
    
        public SingleItemModel(String name, String url) {
            this.name = name;
            this.url = url;
        }
    
    
        public String getUrl() {
            return url;
        }
    
        public void setUrl(String url) {
            this.url = url;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getDescription() {
            return description;
        }
    
        public void setDescription(String description) {
            this.description = description;
        }
    
    
    }
    

    SectionDataModel.java

    package com.pratap.gplaystore.models;
    
    import java.util.ArrayList;
    
    
    public class SectionDataModel {
    
    
    
        private String headerTitle;
        private ArrayList<SingleItemModel> allItemsInSection;
    
    
        public SectionDataModel() {
    
        }
        public SectionDataModel(String headerTitle, ArrayList<SingleItemModel> allItemsInSection) {
            this.headerTitle = headerTitle;
            this.allItemsInSection = allItemsInSection;
        }
    
    
    
        public String getHeaderTitle() {
            return headerTitle;
        }
    
        public void setHeaderTitle(String headerTitle) {
            this.headerTitle = headerTitle;
        }
    
        public ArrayList<SingleItemModel> getAllItemsInSection() {
            return allItemsInSection;
        }
    
        public void setAllItemsInSection(ArrayList<SingleItemModel> allItemsInSection) {
            this.allItemsInSection = allItemsInSection;
        }
    
    
    }
    

    步骤:2

    使用 RecyclerView 创建一个 Activity 以垂直顺序显示列表。

    MainActivity.java

    package com.pratap.gplaystore;
    
    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.support.v7.widget.LinearLayoutManager;
    import android.support.v7.widget.RecyclerView;
    import android.support.v7.widget.Toolbar;
    
    import com.pratap.gplaystore.adapters.RecyclerViewDataAdapter;
    import com.pratap.gplaystore.models.SectionDataModel;
    import com.pratap.gplaystore.models.SingleItemModel;
    
    import java.util.ArrayList;
    
    public class MainActivity extends AppCompatActivity {
    
        private Toolbar toolbar;
    
    
        ArrayList<SectionDataModel> allSampleData;
    
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            toolbar = (Toolbar) findViewById(R.id.toolbar);
    
            allSampleData = new ArrayList<SectionDataModel>();
    
            if (toolbar != null) {
                setSupportActionBar(toolbar);
                toolbar.setTitle("G PlayStore");
    
            }
    
    
            createDummyData();
    
    
            RecyclerView my_recycler_view = (RecyclerView) findViewById(R.id.my_recycler_view);
    
            my_recycler_view.setHasFixedSize(true);
    
            RecyclerViewDataAdapter adapter = new RecyclerViewDataAdapter(this, allSampleData);
    
            my_recycler_view.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
    
            my_recycler_view.setAdapter(adapter);
    
    
        }
    
        public void createDummyData() {
            for (int i = 1; i <= 5; i++) {
    
                SectionDataModel dm = new SectionDataModel();
    
                dm.setHeaderTitle("Section " + i);
    
                ArrayList<SingleItemModel> singleItem = new ArrayList<SingleItemModel>();
                for (int j = 0; j <= 5; j++) {
                    singleItem.add(new SingleItemModel("Item " + j, "URL " + j));
                }
    
                dm.setAllItemsInSection(singleItem);
    
                allSampleData.add(dm);
    
            }
        }
    }
    

    为上述活动类创建一个 XML 布局

    activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            android:elevation="8dp"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
    
    
        <android.support.v7.widget.RecyclerView
            android:id="@+id/my_recycler_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scrollbars="none" />
    
    
    </LinearLayout>
    

    步骤:3

    现在在 MainActivity 中为 recyclerView 创建一个适配器类。

    RecyclerViewDataAdapter.java

    package com.pratap.gplaystore.adapters;
    
    /**
     * Created by pratap.kesaboyina on 24-12-2014.
     */
    
    import android.content.Context;
    import android.support.v7.widget.LinearLayoutManager;
    import android.support.v7.widget.RecyclerView;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.Button;
    import android.widget.TextView;
    import android.widget.Toast;
    
    import com.pratap.gplaystore.R;
    import com.pratap.gplaystore.models.SectionDataModel;
    
    import java.util.ArrayList;
    
    public class RecyclerViewDataAdapter extends RecyclerView.Adapter<RecyclerViewDataAdapter.ItemRowHolder> {
    
        private ArrayList<SectionDataModel> dataList;
        private Context mContext;
    
        public RecyclerViewDataAdapter(Context context, ArrayList<SectionDataModel> dataList) {
            this.dataList = dataList;
            this.mContext = context;
        }
    
        @Override
        public ItemRowHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
            View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.list_item, null);
            ItemRowHolder mh = new ItemRowHolder(v);
            return mh;
        }
    
        @Override
        public void onBindViewHolder(ItemRowHolder itemRowHolder, int i) {
    
            final String sectionName = dataList.get(i).getHeaderTitle();
    
            ArrayList singleSectionItems = dataList.get(i).getAllItemsInSection();
    
            itemRowHolder.itemTitle.setText(sectionName);
    
            SectionListDataAdapter itemListDataAdapter = new SectionListDataAdapter(mContext, singleSectionItems);
    
            itemRowHolder.recycler_view_list.setHasFixedSize(true);
            itemRowHolder.recycler_view_list.setLayoutManager(new LinearLayoutManager(mContext, LinearLayoutManager.HORIZONTAL, false));
            itemRowHolder.recycler_view_list.setAdapter(itemListDataAdapter);
    
    
            itemRowHolder.btnMore.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
    
    
                    Toast.makeText(v.getContext(), "click event on more, "+sectionName , Toast.LENGTH_SHORT).show();
    
    
    
                }
            });
    
    
           /* Glide.with(mContext)
                    .load(feedItem.getImageURL())
                    .diskCacheStrategy(DiskCacheStrategy.ALL)
                    .centerCrop()
                    .error(R.drawable.bg)
                    .into(feedListRowHolder.thumbView);*/
        }
    
        @Override
        public int getItemCount() {
            return (null != dataList ? dataList.size() : 0);
        }
    
        public class ItemRowHolder extends RecyclerView.ViewHolder {
    
            protected TextView itemTitle;
    
            protected RecyclerView recycler_view_list;
    
            protected Button btnMore;
    
    
    
            public ItemRowHolder(View view) {
                super(view);
    
                this.itemTitle = (TextView) view.findViewById(R.id.itemTitle);
                this.recycler_view_list = (RecyclerView) view.findViewById(R.id.recycler_view_list);
                this.btnMore= (Button) view.findViewById(R.id.btnMore);
    
    
            }
    
        }
    
    }
    

    现在为上面的适配器类创建一个 xml 布局文件。

    list_item.xml

    <?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="wrap_content"
    
        android:background="?android:selectableItemBackground"
        android:orientation="vertical"
        android:padding="5dp">
    
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="2dp">
    
    
            <TextView
                android:id="@+id/itemTitle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:layout_alignParentStart="true"
                android:layout_centerVertical="true"
                android:layout_gravity="center_vertical"
                android:layout_toLeftOf="@+id/btnMore"
                android:text="Sample title"
                android:textColor="@android:color/black"
                android:textSize="18sp" />
    
            <Button
                android:id="@+id/btnMore"
                android:layout_width="wrap_content"
                android:layout_height="42dp"
                android:layout_alignParentEnd="true"
                android:layout_alignParentRight="true"
                android:layout_centerVertical="true"
                android:theme="@style/MyButton"
                android:text="more"
                android:textColor="#FFF" />
    
    
        </RelativeLayout>
    
        <android.support.v7.widget.RecyclerView
            android:id="@+id/recycler_view_list"
            android:layout_width="match_parent"
            android:layout_height="160dp"
            android:layout_gravity="center_vertical"
            android:orientation="horizontal" />
    
    
    </LinearLayout>
    

    步骤:4

    现在,为了制作一个水平的 RecyclerView ,我们需要为每一行创建一个布局和 Adapter 类。

    list_single_card.xml

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:cardCornerRadius="5dp"
        app:cardUseCompatPadding="true"
        >
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="0dp"
            android:background="?android:selectableItemBackground"
            android:orientation="vertical">
    
            <ImageView
                android:id="@+id/itemImage"
                android:layout_width="100dp"
                android:layout_height="100dp"
                android:layout_gravity="center_horizontal"
                android:scaleType="fitCenter"
                android:src="@drawable/android" />
    
    
            <TextView
                android:id="@+id/tvTitle"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_below="@id/itemImage"
                android:gravity="center"
                android:padding="5dp"
                android:text="Sample title"
                android:textColor="@android:color/black"
                android:textSize="18sp" />
    
    
        </LinearLayout>
    
    </android.support.v7.widget.CardView>
    

    Horizo​​ntal RecyclerView 的适配器类

    SectionListDataAdapter.java

    package com.pratap.gplaystore.adapters;
    
    /**
     * Created by pratap.kesaboyina on 24-12-2014.
     */
    
    import android.content.Context;
    import android.support.v7.widget.RecyclerView;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.ImageView;
    import android.widget.TextView;
    import android.widget.Toast;
    
    import com.pratap.gplaystore.R;
    import com.pratap.gplaystore.models.SingleItemModel;
    
    import java.util.ArrayList;
    
    public class SectionListDataAdapter extends RecyclerView.Adapter<SectionListDataAdapter.SingleItemRowHolder> {
    
        private ArrayList<SingleItemModel> itemsList;
        private Context mContext;
    
        public SectionListDataAdapter(Context context, ArrayList<SingleItemModel> itemsList) {
            this.itemsList = itemsList;
            this.mContext = context;
        }
    
        @Override
        public SingleItemRowHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
            View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.list_single_card, null);
            SingleItemRowHolder mh = new SingleItemRowHolder(v);
            return mh;
        }
    
        @Override
        public void onBindViewHolder(SingleItemRowHolder holder, int i) {
    
            SingleItemModel singleItem = itemsList.get(i);
    
            holder.tvTitle.setText(singleItem.getName());
    
    
           /* Glide.with(mContext)
                    .load(feedItem.getImageURL())
                    .diskCacheStrategy(DiskCacheStrategy.ALL)
                    .centerCrop()
                    .error(R.drawable.bg)
                    .into(feedListRowHolder.thumbView);*/
        }
    
        @Override
        public int getItemCount() {
            return (null != itemsList ? itemsList.size() : 0);
        }
    
        public class SingleItemRowHolder extends RecyclerView.ViewHolder {
    
            protected TextView tvTitle;
    
            protected ImageView itemImage;
    
    
            public SingleItemRowHolder(View view) {
                super(view);
    
                this.tvTitle = (TextView) view.findViewById(R.id.tvTitle);
                this.itemImage = (ImageView) view.findViewById(R.id.itemImage);
    
    
                view.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
    
    
                        Toast.makeText(v.getContext(), tvTitle.getText(), Toast.LENGTH_SHORT).show();
    
                    }
                });
    
    
            }
    
        }
    
    }
    

    就是这样!

    http://android-pratap.blogspot.com.ng/2015/12/horizontal-recyclerview-in-vertical.html

    【讨论】:

    • 嗨,如果我想要整个 recyclerview 有水平滚动和垂直行怎么办stackoverflow.com/questions/41675989/…
    • 我认为这不会像预期的那样工作(除了我没有得到你的问题),即使它不是一个好的设计布局,因为 recyclerview 的主要本质现在已经被征服了。如果你问我这有点搞砸了,你正在尝试实现的是 recyclerview 中的网格视图。
    • 如何获取第二行第三项的位置?
    • 在 MainActivity 中玩弄这个逻辑(createDummyData() 函数)。如果 i = 2 表示第二行,j = 2 表示第三项。这是第二行的第三项。
    【解决方案2】:

    因此,对于您的前两个视图,我建议您使用HorizontalListView,然后对于其他项目,如果它们总是连续 6 个正方形,请创建一些简单的 LinearLayout 水平方向和 6 个内部视图。至于整个布局使用普通的ListView

    ListView 中使用HorizontalListView 并没有什么特别之处,因为它们在不同的轴上滚动,但是在你的适配器中你必须实现getItemViewType(int position)getViewTypeCount(),因为你有两种不同类型的视图你的布局,使用这种方法,android 知道在你的convertView 中提供什么样的视图以供在getView(int position, View convertView, ViewGroup parent) 中重用。 并且使用这种机制 - 视图回收将完美运行,因为它最多会创建 2 个HorizontalListView 和大约 8 个其他视图项。

    【讨论】:

    • 我遇到的问题是,Horizo​​ntalListView 似乎正在从 ListView 中窃取垂直滑动......并且在我的屏幕充满了 Horizo​​ntalListViews 的情况下,我无法让它滚动垂直...有没有办法让 Horizo​​ntalListViews 将垂直滑动传递给它的父级?
    • 另外,我相信,Horizo​​ntalListView 没有用于视图回收的适配器......所以我需要使用画廊???
    • 嗯,是的,我只记得当我结合使用 Horizo​​ntalScrollView 和普通视图时,我使用普通视图滚动 ListView,是的,Horizo​​ntalScrollView 正在窃取触摸。然后您可以尝试自定义一些 Horizo​​ntalScrollView 并覆盖 onTouch 事件以使其始终返回 false,这样您也可以将触摸传播到 ListView。
    • 现在关于视图回收,是的,你是对的,它不会回收视图,你可以使用 Gallery,但这是一个已弃用的 API,所以你应该问自己一个问题是否真的如此一排有多少物品需要横向回收?
    • 好的,我测试了从 onTouch 返回 false 并没有帮助 :) 所以应该有别的东西。
    猜你喜欢
    • 1970-01-01
    • 2015-12-21
    • 1970-01-01
    • 1970-01-01
    • 2023-04-07
    • 2015-01-27
    • 2015-08-04
    • 2017-02-03
    相关资源
    最近更新 更多