动态生成多个Gridview

时间:2015-01-22 01:54:11

标签: android android-layout android-gridview

我从API中获取一些内容,我需要在Android应用中显示。内容采用JSON格式,如下所示:

{
  "items": [
    {
      "catalog_items": [
        {
          "date": "23-01-2015", 
          "content": "Trimmer 1 description", 
          "name": "Trimmer 1"
        }, 
        {
          "date": "25-01-2015", 
          "content": "Trimmer 2 description", 
          "name": "Trimmer 2"
        }
        .....
        .....
      ], 
      "item_category": "Trimmer"
    }, 
    {
      "catalog_items": [
        {
          "date": "13-08-2014", 
          "content": "Shirt description here", 
          "name": "John Player Shirt"
        }
      ], 
      "item_category": "Shirts"
    }, 
    {
      "item_category": "Woolen"
    }
  ], 
  "pages": [
    {
      "date": "24-01-2015", 
      "content": "This is some content about page 1", 
      "name": "Sample Page title 1"
    }, 
    {
      "date": "26-01-2015", 
      "content": "This is some content about page 2", 
      "name": "Sample Page title 2"
    }
  ]
}

我必须在app中创建一个仪表板,它基于以上JSON数据以下列方式构建:

Top Menu
=====================
Trimmers (Gridview)

Trimmer1    Trimmer2
Trimmer3    Trimmer4

======================
Shirts (Gridview)

John Players

======================
Pages (Listview)

Page1
Page2

My Dashboard Fragment获取此JSON。我的仪表板布局是:

fragment_home.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/relativeLayout1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
</RelativeLayout>

和我的仪表板活动如下所示:

public class HomeFragment extends Fragment {
   .....
   .....
   @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
      View rootView = inflater.inflate(R.layout.fragment_home, container, false);
      try {

            JSONObject obj = new JSONObject(loadJSONFromAsset("input.json"));
            if(obj.has("catagories")) {
                JSONArray catag = obj.getJSONArray("items");
                for(int i=0; i< catag.length();i++){
                    JSONObject catitem = catag.getJSONObject(i);
                    JSONArray posts = catitem.getJSONArray("catalog_items");
                    for(int j=0;j<posts.length();j++){
                        JSONObject postitem = posts.getJSONObject(j);
                        catList.add(postitem.getString("name"));
                    }

                    addGridtoLayout(catitem.getString("item_category"),catList);
                }
            }
        } catch (JSONException e){
            e.printStackTrace();
        }

        return rootView;

}
    public void addGridtoLayout(String title, ArrayList<String> itemList)
        {
            RelativeLayout ll = new RelativeLayout(getActivity());
            RelativeLayout.LayoutParams parambs = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
            ll.setLayoutParams(parambs);


            TextView tv = new TextView(getActivity());
            tv.setText(title);
            tv.setId(R.id.layout1);

            RelativeLayout.LayoutParams lay = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
            ll.addView(tv, lay);

            GridView gridView= new GridView(getActivity());
            gridView.setLayoutParams(new GridView.LayoutParams(GridLayout.LayoutParams.MATCH_PARENT, GridLayout.LayoutParams.MATCH_PARENT));
            gridView.setNumColumns(GRID_COL_NUM);
            gridView.setAdapter(new HomeGridAdapter(getActivity(), itemList));
            RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
            params.addRule(RelativeLayout.BELOW, tv.getId());
            ll.addView(gridView, params);

            mainLayout.addView(ll);
        }

这是仅用于项目的代码(Gridview)。

我要做的是基本上将每个gridview和标题包装在relativelayout中。从第一项开始,相对布局将显示在前一个布局下方。 但是网格视图相互堆叠,所有项目都显示在一行中。

是否有任何方法可以将每个gridview的相对布局定义为显示在前一个网格视图下方?另外,有没有更好的方法来实现这一目标?我的意思是基本要求是生成动态数量的网格视图。那么生成布局是否只是这样做的方法?

感谢您阅读这篇长篇文章。

1 个答案:

答案 0 :(得分:2)

好吧,正如我在comment中提到的,我做了一些略微修改过的代码,这真的很棒。所以我要详细说明我的所作所为。也许它可以帮助别人。

由于我必须生成多个分段的Gridview,我最初想到使用TableLayout生成表并向其添加TableRows。每个Tablerow都将持有一个RelativeView consiting:

  1. 项目图片(来自JSON)
  2. 项目名称(来自JSON)
  3. 所以,我最初创建了这段代码:

    <强> HomeFragment.java

    public class HomeFragment extends Fragment {
       .....
       .....
    
        ArrayList<String> itemList;
        private JsonHelper jsonHelper;
        private static final int GRID_COL_NUM = 3;
        TableRow tbh;
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
    
        View rootView = inflater.inflate(R.layout.fragment_home, container,false);
        TableLayout table = (TableLayout) rootView.findViewById(R.id.tableLayout);
        table.setStretchAllColumns(true);
        table.setShrinkAllColumns(true);
    
        try {
            JSONObject obj = new JSONObject(loadJSONFromAsset("input.json"));
            if(obj.has("catagories")) {
               JSONArray catag = obj.getJSONArray("items");
               for(int i=0; i< catag.length();i++){
                  JSONObject catitem = catag.getJSONObject(i);
                  JSONArray items = catitem.getJSONArray("catalog_items");
                  if(items.length() > 0) {
                     //Add a Grid Title for this category (span=6, full width)
                     TableRow tbr = addRowTitle(catitem.getString("cat_name"));
                     table.addView(tbr); //Add this title row to the table
    
                     itemList = new ArrayList<>(); //Hold all items for each category
                     for(int j=0;j<items.length();j++){
                         JSONObject singleItem = items.getJSONObject(j);
                         //I am trying to show only 3 items in a row, so add new row after 3
                         if(j % 3 == 0){
                            tbh = addRowGrid(); //add new row and repeat so after 3
                             table.addView(tbh); //Add this to the table, we will fill items below
                         }
    
                         LinearLayout lnr = new LinearLayout(getActivity());
                         TableRow.LayoutParams params = new TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT,TableRow.LayoutParams.WRAP_CONTENT);
                         params.gravity = Gravity.CENTER; //Center the items
                         lnr.setLayoutParams(params);
                         lnr.setOrientation(LinearLayout.VERTICAL); //As per your need. worked for me
    
                         //Item's Image
                         ImageView itemImg = new ImageView(getActivity());                          itemImg.setImageResource(R.drawable.ic_communities); //Default icon for item
    
    
                         TextView itemLabel = new TextView(getActivity());
                         itemLabel.setText(singleItem.getString("name"));
                         itemLabel.setTypeface(Typeface.SERIF, Typeface.BOLD);
    
                         lnr.addView(postImg,params);
                         lnr.addView(postLabel,params);
                         tbh.addView(lnr); //Now we have image and content, wrap in linear layout and add to the row.
                         itemList.add(singleItem.getString("name")); //This step is not needed for now. I just wrote this to use this array for other purposes.
                      }
            //I am all confused at this point if I have really closed all of curly braces. Please confirm
                   }
                }
             }
         } catch (JSONException e){
                e.printStackTrace();
         }
    
         return rootView;
    
      }
    
      public TableRow addRowGrid()
      {
            return new TableRow(getActivity());
      }
    
      public TableRow addRowTitle(String titleb)
      {
            TableRow rowTitle = new TableRow(getActivity());
            rowTitle.setGravity(Gravity.CENTER_HORIZONTAL);
            // title column/row
            TextView title = new TextView(getActivity());
            title.setText(titleb);
    
            title.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18);
            title.setGravity(Gravity.CENTER);
            title.setTypeface(Typeface.SERIF, Typeface.BOLD);
    
            TableRow.LayoutParams params = new TableRow.LayoutParams();
            params.span = 6;
    
            rowTitle.addView(title, params);
            return rowTitle;
      }
    ...
    ...
    }
    

    这整个代码适用于布局中定义的单个Table布局: 的 fragment_home

    <?xml version="1.0" encoding="utf-8"?>
    <ScrollView
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/card_scrollview"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentTop="true">
    <RelativeLayout
        android:id="@+id/relativeLayout1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    
        <TableLayout
            android:id="@+id/tableLayout"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true"></TableLayout>
    
    </RelativeLayout>
    </ScrollView>
    

    所以整个表都是动态生成的。工作得很好。我可以在每一行上附加一个点击处理程序来监听,我可能需要为每个视图设置标记以获取被点击的项目。然后我想到了更可行和灵活的方法。如果我将gridview添加到每一行本身,而不是将LinearLayouts附加到每个TableRows,该怎么办?所以,我最终修改了这种方法的代码: 1.单个TableRow将保存每个类别标题,并将附加第二个Tablerow,它将保存gridview。 2.我现在可以使用自定义网格适配器,通过它可以更好地更改每个项目的布局,即通过XML而不是在这里“即时”方法。 上面的点也让我获得了一个clicklistener。因此不需要设置标签。

    注意:上述方法正在起作用,以下方法也在起作用(同样)。所以你可以同时使用

    因此,我创建了一个函数,它将为每个项目类别添加标题,并创建一个函数将项目添加到网格,并将网格添加到一行:

    HomeFragment.java(gridview版本)

    public class HomeFragment extends Fragment {
    
        private static final int GRID_COL_NUM = 3;
        TableRow tbh;
    
        public HomeFragment(){}
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
    
            View rootView = inflater.inflate(R.layout.fragment_home, container, false);
            TableLayout table = (TableLayout) rootView.findViewById(R.id.tableLayout);
            table.setStretchAllColumns(true);
            table.setShrinkAllColumns(true);
    
            try {
    
                JSONObject obj = new JSONObject(loadJSONFromAsset("input.json"));
                if(obj.has("catagories")) {
                    JSONArray catag = obj.getJSONArray("catagories");
                    for(int i=0; i< catag.length();i++) {
                        JSONObject catitem = catag.getJSONObject(i);
                        if (catitem.has("items")) {
                            JSONArray items = catitem.getJSONArray("catalog_items");
                            if (items.length() > 0) {
                                //Add row with title catname
                                TableRow tbr = addRowTitle(catitem.getString("cat_name")); //Add category Name as title
                                table.addView(tbr); //Same I did previously
    
                                ArrayList<String> itemList = new ArrayList<>();
                                for (int j = 0; j < items.length(); j++) {
                                    JSONObject singleItem = posts.getJSONObject(j);
                                    itemList.add(singleItem.getString("name"));
                                }
    
                                tbh = addGridRow(itemList); //Create Grid of collections and add it to a tablerow
                                table.addView(tbh); //Add this tablerow to table
                            }
                        }
                    }
                }
                if(obj.has("pages")) {
                    JSONArray pages = obj.getJSONArray("pages");
                    if(pages.length() > 0) {
                        TableRow tbr = addRowTitle("Pages");
                        table.addView(tbr);
    
                        ArrayList<String> pageList = new ArrayList<>();
                        for (int i = 0; i < pages.length(); i++) {
                            JSONObject page = pages.getJSONObject(i);
                            pageList.add(page.getString("name"));
                        }
                        tbh = addGridRow(pageList);
                        table.addView(tbh);
                    }
                }
            } catch (JSONException e){
                e.printStackTrace();
            }
    
            return rootView;
        }
    
    /**
    * Now this is a life saver. Gridviews aren't friendly with scrollviews (I might be wrong, but happens with me everytime), especially if generated dynamically. Hence this function calculates height of each item of gridview dynamically and hence sets the total view height adapted from https://stackoverflow.com/a/22555947/1136491
    **/
        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);
    
        }
    
        public TableRow addGridRow(ArrayList gridItemList)
        {
            TableRow gridrow = new TableRow(getActivity());
            GridView gv = new GridView(getActivity());
            TableRow.LayoutParams params = new TableRow.LayoutParams(
                    TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT);
            gv.setLayoutParams(params);
            gv.setNumColumns(GRID_COL_NUM); //3 columns grid 
            gv.setAdapter(new HomeGridAdapter(getActivity(), gridItemList)); //Custom grid adapter I was talking about. See Below
            gridrow.addView(gv);
    //Thanks for not messing up my gridview inside scrollview
            setGridViewHeightBasedOnChildren(gv,GRID_COL_NUM); //3 Columns
            return gridrow;
        }
    
    //Simply add title above the gridview
        public TableRow addRowTitle(String titleb)
        {
            TableRow rowTitle = new TableRow(getActivity());
            rowTitle.setGravity(Gravity.CENTER_HORIZONTAL);
            // title column/row
            TextView title = new TextView(getActivity());
            title.setText(titleb);
    
            title.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18);
            title.setGravity(Gravity.CENTER);
            title.setTypeface(Typeface.SERIF, Typeface.BOLD);
    
            TableRow.LayoutParams params = new TableRow.LayoutParams();
            params.span = 6;
    
            rowTitle.addView(title, params);
            return rowTitle;
        }
    ....
    }
    

    现在我的自定义适配器 的 HomeGridAdapter.java

    public class HomeGridAdapter extends BaseAdapter {
        ArrayList<String> result;
        Context context;
    
        private static LayoutInflater inflater=null;
        public HomeGridAdapter(Context context, ArrayList<String> itemList) {
            // TODO Auto-generated constructor stub
            this.result=itemList;
            this.context=context;
            inflater = ( LayoutInflater )context.
                    getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    
        }
    
        @Override
        public int getCount() {
            // TODO Auto-generated method stub
            return result.size();
        }
    
        @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;
        }
    
        public class Holder
        {
            TextView tv;
            ImageView img;
        }
        @Override
        public View getView(final int position, View convertView, ViewGroup parent) {
            // TODO Auto-generated method stub
            Holder holder=new Holder();
            View rowView;
            //Layout mentioned below
            rowView = inflater.inflate(R.layout.home_grid_layout, null);
            holder.tv=(TextView) rowView.findViewById(R.id.textView1);
            holder.img=(ImageView) rowView.findViewById(R.id.imageView1);
            //Item's Text
            holder.tv.setText(result.get(position));
            //Item's Image
            holder.img.setImageResource(R.drawable.ic_launcher);
            //A click listener to each gid item
            rowView.setOnClickListener(new View.OnClickListener() {
    
                @Override
                public void onClick(View v) {
                    // TODO Auto-generated method stub
                    Toast.makeText(context, "You Clicked "+result.get(position), Toast.LENGTH_SHORT).show();
                }
            });
    
            return rowView;
        }
    
    }
    

    <强> home_grid_layout.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="match_parent"
    
        android:orientation="vertical" >
    
        <ImageView
            android:id="@+id/imageView1"
            android:layout_gravity="center"
            android:layout_width="88dp"
            android:layout_height="88dp"
            android:layout_marginTop="5dp"
            android:layout_marginBottom="5dp"
            android:src="@drawable/ic_launcher" />
    
        <TextView
            android:id="@+id/textView1"
            android:layout_gravity="center"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="15dp"
            android:layout_marginTop="5dp"
            android:layout_marginBottom="5dp"
            android:text="TextView" />
    
    </LinearLayout>
    

    所以我目前正在使用TableLayout的Gridview版本。我可能已经实现了我想要的东西,但我真的很欢迎这里有任何建议。希望这个答案能给别人一个很大的帮助。

    感谢您坚持这么久。