2016-05-11 55 views
1

我想將動態按鈕添加到網格佈局,如下所示。 每個按鈕每次添加一個,並且佈局必須自行更新以使按鈕在行中。 我的問題是,當添加一個新按鈕時,它會出現在添加的最後一個按鈕的頂部,而不是以行格式放置。在下面的這張圖片中,我展示了我想要的以及當前發生的事情,標有數字的正方形是我的按鈕。在我所擁有的圖像中,我已經在佈局中添加了6個按鈕,但它們全部相互重疊。使用RecyclerView添加到GridLayout的動態按鈕相互重疊添加

enter image description here

我已經看了看周圍有關如何做到這一點,有人建議,我認爲我使用RecyclerViewGridLayoutManager。我已經添加了這個到我的代碼,但就像我說的問題是,當我添加一個按鈕,然後如果我添加另一個按鈕,第二個被添加到第一個。我有什麼作品,如果我的按鈕是預設的,但不適用於動態按鈕。

這裏是我的代碼:

主要碎片啓動RecyclerView。我有另一項活動,啓動createButton()方法並通過可繪製字符串。這些繪圖和字符串根據用戶的操作逐個傳遞給此方法,並一次創建一個圖像按鈕。

public class MyFragment extends Fragment { 

    private GridLayoutManager lLayout; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

    } 

    // onCreateView 
    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
     View view = inflater.inflate(R.layout.my_fragment, container, false); 

     // Get screen size to have different layouts for phone and tablet 
     int screenSize = getResources().getConfiguration().screenLayout & 
       Configuration.SCREENLAYOUT_SIZE_MASK; 

     String toastMsg; 
     switch (screenSize) { 
      case Configuration.SCREENLAYOUT_SIZE_LARGE: 
       toastMsg = "Large screen"; 
       Log.d("tag_name", "Large screen"); 
       break; 
      case Configuration.SCREENLAYOUT_SIZE_NORMAL: 
       toastMsg = "Normal screen"; 
       Log.d("tag_name", "Normal screen"); 
       break; 
      case Configuration.SCREENLAYOUT_SIZE_SMALL: 
       toastMsg = "Small screen"; 
       Log.d("tag_name", "Small screen"); 
       break; 
      default: 
       toastMsg = "Screen size is neither large, normal or small"; 
       Log.d("tag_name", "Screen size is not large, normal, or small"); 
     } 
     Toast.makeText(getActivity(), toastMsg, Toast.LENGTH_LONG).show(); 

     // Create an empty list to initialize the adapter (or else get nullPointerException error) 
     List<ItemObject> myList = new ArrayList<ItemObject>(); 

     // 3 rows for tablet 
     // 2 rows for phone 

     if (screenSize == Configuration.SCREENLAYOUT_SIZE_LARGE 
       || screenSize == Configuration.SCREENLAYOUT_SIZE_XLARGE) { 
      lLayout = new GridLayoutManager(getActivity(), 3, GridLayoutManager.HORIZONTAL, false); 
     } else 
      lLayout = new GridLayoutManager(getActivity(), 2, GridLayoutManager.HORIZONTAL, false); 

     RecyclerView rView = (RecyclerView) view.findViewById(R.id.recycler_view); 

     rView.setHasFixedSize(true); 
     rView.setLayoutManager(lLayout); 

     RecyclerViewAdapter rcAdapter = new RecyclerViewAdapter(getActivity(), myList); 
     rView.setAdapter(rcAdapter); 

     return view; 
    } 

    private List<ItemObject> getAllItemList(String applicationName, Drawable app_drawable) { 

     List<ItemObject> allItems = new ArrayList<ItemObject>(); 
     allItems.add(new ItemObject(applicationName, app_drawable)); 

     return allItems; 
    } 

    public void createButton(Drawable d, String appName) { 

     List<ItemObject> rowListItem = getAllItemList(appName, d); 
     lLayout = new GridLayoutManager(getActivity(), 2, GridLayoutManager.HORIZONTAL, false); 


     RecyclerView rView = (RecyclerView) getView().findViewById(R.id.recycler_view); 
     rView.setHasFixedSize(true); 
     rView.setLayoutManager(lLayout); 

     RecyclerViewAdapter rcAdapter = new RecyclerViewAdapter(getActivity(), rowListItem); 
     rView.setAdapter(rcAdapter); 

    } 

} 

我的佈局(my_fragment):

<LinearLayout android:id="@+id/my_fragment" 
      xmlns:android="http://schemas.android.com/apk/res/android" 
      android:layout_width="match_parent" 
      android:layout_height="match_parent" 
      android:layout_marginTop="15dp" 
      android:gravity="center_horizontal"> 

    <android.support.v7.widget.RecyclerView 
     android:id="@+id/recycler_view" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:scrollbars="horizontal"/> 

    <RelativeLayout 
     android:layout_width="match_parent" 
     android:layout_height="match_parent"> 

     <ImageButton 
      android:id="@+id/new_app_button" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content"/> 

     <TextView 
      android:id="@+id/new_app_name" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:layout_below="@+id/new_app_button" 
      android:gravity="center"/> 

    </RelativeLayout> 
</LinearLayout> 

編輯

這是我更新的代碼FOR MyFragment 現在我得到一個NullPointerException當第二的ImageButton被添加

public class MyFragment extends Fragment { 

private GridLayoutManager lLayout; 

private ButtonCreator bc; 
RecyclerViewAdapter rcAdapter; 


@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 

    List<ItemObject> myList = new ArrayList<ItemObject>(); 
    rcAdapter = new RecyclerViewAdapter(getActivity(),myList); 

} 

// onCreateView 
@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
    View view = inflater.inflate(R.layout.home_fragment, container, false); 


    // Get screen size so we can have different layouts for phone and tablet 
    int screenSize = getResources().getConfiguration().screenLayout & 
      Configuration.SCREENLAYOUT_SIZE_MASK; 

    String toastMsg; 
    switch(screenSize) { 
     case Configuration.SCREENLAYOUT_SIZE_LARGE: 
      toastMsg = "Large screen"; 
      Log.d("tag_name", "Large screen"); 
      break; 
     case Configuration.SCREENLAYOUT_SIZE_NORMAL: 
      toastMsg = "Normal screen"; 
      Log.d("tag_name", "Normal screen"); 
      break; 
     case Configuration.SCREENLAYOUT_SIZE_SMALL: 
      toastMsg = "Small screen"; 
      Log.d("tag_name", "Small screen"); 
      break; 
     default: 
      toastMsg = "Screen size is neither large, normal or small"; 
      Log.d("tag_name", "Screen size is not large, normal, or small"); 
    } 
    Toast.makeText(getActivity(), toastMsg, Toast.LENGTH_LONG).show(); 


    // Create an empty list to initialize the adapter (or else get nullPointerException error) 

    if (screenSize == Configuration.SCREENLAYOUT_SIZE_LARGE 
    || screenSize == Configuration.SCREENLAYOUT_SIZE_XLARGE) { 
     lLayout = new GridLayoutManager(getActivity(), 3, GridLayoutManager.HORIZONTAL, false); 
    } 

    else lLayout = new GridLayoutManager(getActivity(), 2, GridLayoutManager.HORIZONTAL, false); 


    RecyclerView rView = (RecyclerView)view.findViewById(R.id.recycler_view); 

    rView.setHasFixedSize(true); 
    rView.setLayoutManager(lLayout); 


    rView.setAdapter(rcAdapter); 


    return view; 
} 

private List<ItemObject> getAllItemList(String applicationName, Drawable app_drawable){ 

    List<ItemObject> allItems = new ArrayList<ItemObject>(); 
    allItems.add(new ItemObject(applicationName, app_drawable)); 


    return allItems; 
} 


public void createButton (Drawable d, String appName){ 

    rcAdapter.addItem(new ItemObject(appName , d)); 

} 



// In order to get the view of HomeFragment correctly 

public interface ButtonCreator{ 
    void buttonCreator(Drawable d, String string); 
} 



@Override 
public void onAttach(Activity activity) { 
    super.onAttach(activity); 
    bc = (ButtonCreator) activity; 
} 

} 

如何我打電話MyFragment createButton方法(稱爲在runOnUiThread法)

public class MainActivity extends FragmentActivity implements MyFragment.ButtonCreator { 


private Thread repeatTaskThread; 
private byte[] byteArray; 

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 

    FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); 
    ft.replace(R.id.container, new MyFragment()).commit(); 
} 


public void buttonCreator(Drawable d,String a) { 
    MyFragment homeFragment = (MyFragment)getSupportFragmentManager().getFragments().get(1); 
    homeFragment.createButton(d, a); 
} 

public void RepeatTask(){ 

    repeatTaskThread = new Thread() { 
     public void run() { 
      while (true) { 


       try { 


       System.out.println("TRY_1"); 

       Socket socket = new Socket("192.168.0.26", 5050); 

       // Get data sent through socket 
       DataInputStream DIS = new DataInputStream(socket.getInputStream()); 

       System.out.println("DataInputStream Started"); 

       // read data that got sent 
       final String applicationName = DIS.readUTF(); 


       // read array data for bitmap 

       int len = DIS.readInt(); 
       byte[] data = new byte[len]; 

       DIS.readFully(data, 0, data.length); 


       Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); 
       final Drawable d = new BitmapDrawable(getResources(), bitmap); 


        runOnUiThread(new Runnable() { 
        @Override 
        public void run() { 
         // TODO Auto-generated method stub 


         Log.d("tag_name", "Try_2"); 

         buttonCreator(d,applicationName); 


        } 
       }); 


       socket.close(); 




       } catch (Exception e) { 


       System.out.println("Exception is " + e.toString()); 

       } 


       try { 
       // Sleep for 5 seconds 
       Thread.sleep(5000); 
       } catch (Exception e) { 
       e.printStackTrace(); 
       } 
      } 
     } 

     ; 
    }; 
    repeatTaskThread.start(); 


} 

} 

我的錯誤時的第二個按鈕創建我的應用程序崩潰:

05-11 17:05:25.275 14257-14257/it.anddev.bradipao.janus E/RecyclerView: No adapter attached; skipping layout 
05-11 17:05:25.275 14257-14257/it.anddev.bradipao.janus D/AndroidRuntime: Shutting down VM 
05-11 17:05:25.275 14257-14257/it.anddev.bradipao.janus W/dalvikvm: threadid=1: thread exiting with uncaught exception (group=0x437c0160) 
05-11 17:05:25.305 14257-14257/it.anddev.bradipao.janus E/AndroidRuntime: FATAL EXCEPTION: main 
                     Process: it.anddev.bradipao.janus, PID: 14257 
                     java.lang.NullPointerException 
                      at android.support.v7.widget.RecyclerView.computeHorizontalScrollRange(RecyclerView.java:1518) 
                      at android.view.View.onDrawScrollBars(View.java:12248) 
                      at android.view.View.draw(View.java:14794) 
                      at android.support.v7.widget.RecyclerView.draw(RecyclerView.java:3171) 
                      at android.view.View.getDisplayList(View.java:13655) 
                      at android.view.View.getDisplayList(View.java:13697) 
                      at android.view.View.draw(View.java:14505) 
                      at android.view.ViewGroup.drawChild(ViewGroup.java:3134) 
                      at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2971) 
                      at android.view.View.getDisplayList(View.java:13650) 
                      at android.view.View.getDisplayList(View.java:13697) 
                      at android.view.View.draw(View.java:14505) 
                      at android.view.ViewGroup.drawChild(ViewGroup.java:3134) 
                      at android.support.v7.widget.RecyclerView.drawChild(RecyclerView.java:3693) 
                      at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2971) 
                      at android.view.View.draw(View.java:14791) 
                      at android.support.v7.widget.RecyclerView.draw(RecyclerView.java:3171) 
                      at android.view.View.getDisplayList(View.java:13655) 
                      at android.view.View.getDisplayList(View.java:13697) 
                      at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3108) 
                      at android.view.View.getDisplayList(View.java:13593) 
                      at android.view.View.getDisplayList(View.java:13697) 
                      at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3108) 
                      at android.view.View.getDisplayList(View.java:13593) 
                      at android.view.View.getDisplayList(View.java:13697) 
                      at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3108) 
                      at android.view.View.getDisplayList(View.java:13593) 
                      at android.view.View.getDisplayList(View.java:13697) 
                      at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3108) 
                      at android.view.View.getDisplayList(View.java:13593) 
                      at android.view.View.getDisplayList(View.java:13697) 
                      at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3108) 
                      at android.view.View.getDisplayList(View.java:13593) 
                      at android.view.View.getDisplayList(View.java:13697) 
                      at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3108) 
                      at android.view.View.getDisplayList(View.java:13593) 
                      at android.view.View.getDisplayList(View.java:13697) 
                      at android.view.HardwareRenderer$GlRenderer.buildDisplayList(HardwareRenderer.java:1570) 
                      at android.view.HardwareRenderer$GlRenderer.draw(HardwareRenderer.java:1449) 
                      at android.view.ViewRootImpl.draw(ViewRootImpl.java:2476) 
                      at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2300) 
                      at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1929) 
                      at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1043) 
                      at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5885) 
                      at android.view.Choreographer$CallbackRecord.run(Choreographer.java:771) 
                      at android.view.Choreographer.doCallbacks(Choreographer.java:574) 
                      at android.view.Choreographer.doFrame(Choreographer.java:544) 
                      at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:757) 
                      at android.os.Handler.handleCallback(Handler.java:733) 
                      at android.os.Handler.dispatchMessage(Handler.java:95) 
                      at android.os.Looper.loop(Looper.java:149) 
                      at android.app.ActivityThread.main(ActivityThread.java:5257) 
                      at java.lang.reflect.Method.invokeNative(Native Method) 
                      at java.lang.reflect.Method.invoke(Method.java:515) 
                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:788) 
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:604) 
                      at dalvik.system.NativeStart.main(Native Method) 
+0

我看到每次需要創建一個按鈕時,您都將重新初始化recyclerView,結果是使用該按鈕創建了一個新的recyclerView。 – varunkr

+0

@varunkr我明白了!所以我想我每次在myFragment的createButton方法中初始化recyclerView的權利?那麼您是否知道如何更改此代碼進行更新,而不是每次創建新的回收站視圖? – Natalie

+0

看看我的回答 – varunkr

回答

1

做這樣的事情

public class MyFragment extends Fragment { 

    private GridLayoutManager lLayout; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

    } 

    // onCreateView 
    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
     View view = inflater.inflate(R.layout.my_fragment, container, false); 

     // Get screen size to have different layouts for phone and tablet 
     int screenSize = getResources().getConfiguration().screenLayout & 
       Configuration.SCREENLAYOUT_SIZE_MASK; 

     String toastMsg; 
     switch (screenSize) { 
      case Configuration.SCREENLAYOUT_SIZE_LARGE: 
       toastMsg = "Large screen"; 
       Log.d("tag_name", "Large screen"); 
       break; 
      case Configuration.SCREENLAYOUT_SIZE_NORMAL: 
       toastMsg = "Normal screen"; 
       Log.d("tag_name", "Normal screen"); 
       break; 
      case Configuration.SCREENLAYOUT_SIZE_SMALL: 
       toastMsg = "Small screen"; 
       Log.d("tag_name", "Small screen"); 
       break; 
      default: 
       toastMsg = "Screen size is neither large, normal or small"; 
       Log.d("tag_name", "Screen size is not large, normal, or small"); 
     } 
     Toast.makeText(getActivity(), toastMsg, Toast.LENGTH_LONG).show(); 

     // Create an empty list to initialize the adapter (or else get nullPointerException error) 

     // 3 rows for tablet 
     // 2 rows for phone 

     if (screenSize == Configuration.SCREENLAYOUT_SIZE_LARGE 
       || screenSize == Configuration.SCREENLAYOUT_SIZE_XLARGE) { 
      lLayout = new GridLayoutManager(getActivity(), 3, GridLayoutManager.HORIZONTAL, false); 
     } else 
      lLayout = new GridLayoutManager(getActivity(), 2, GridLayoutManager.HORIZONTAL, false); 

     RecyclerView rView = (RecyclerView) view.findViewById(R.id.recycler_view); 

     rView.setHasFixedSize(true); 
     rView.setLayoutManager(lLayout); 

     rView.setAdapter(rcAdapter); 

     return view; 
    } 

    RecyclerViewAdapter rcAdapter; 

    private List<ItemObject> getAllItemList(String applicationName, Drawable app_drawable) { 

     List<ItemObject> allItems = new ArrayList<ItemObject>(); 
     allItems.add(new ItemObject(applicationName, app_drawable)); 

     return allItems; 
    } 

    public void createButton(Drawable d, String appName) { 

     rcAdapter.addItem(new ItemObject(appName , d)) 

    } 

} 

並在適配器中添加此方法

public void addItem(int position) { 
     list.add(position); 
     notifyItemInserted(position); 
     notifyItemRangeChanged(position, list.size()); 
    } 

編輯

爲了防止警告試試你的適配器初始化移動的onCreate

@Override 
     public void onCreate(Bundle savedInstanceState) { 
      super.onCreate(savedInstanceState); 
      List<ItemObject> myList = new ArrayList<ItemObject>(); 
      rcAdapter = new RecyclerViewAdapter(getActivity(), myList); 
     } 
+0

謝謝!對於我的addItem,我必須使用下面的代碼:「public void addItem(ItemObject item){ mList.add(item); notifyItemInserted(mList.size() - 1); }」這樣我就不會錯誤,並可以建立我的gradle。當我得到我的圖像按鈕的第一個圖像時,我收到警告「沒有附加適配器:跳過佈局」,但我的圖像按鈕被創建正常。但後來當我嘗試向佈局添加第二個圖像按鈕時,我得到了相同的警告,同時我的應用程序崩潰給出一個nullPointerException。是否有任何明顯的事情可以導致這種情況? – Natalie

+0

@Natalie你可以引用你得到的確切的空指針異常: – varunkr

+0

@Natalie還可以看看編輯! – varunkr

1

當你創建一個按鈕,你應該只需要做兩兩件事:

  1. 更新支持RecyclerView的數據結構10適配器
  2. 通知該數據已使用的適配器的notify...()方法改變了其中一個適配器(有several of them,使用最適用的一個)

您當前的代碼似乎沒有做任何的這些的東西。您也不需要創建或設置任何新的適配器或佈局管理器。

對於您的情況,您將在您的適配器類所持有的列表中添加一個元素,然後使用適當的位置調用notifyItemInserted()。您可以通過添加一個方法到您的適配器都做一次:

public void addItem(ItemObject item) { 
    mList.add(item); 
    notifyItemInserted(mList.size() - 1); 
} 

無關:在Android上可以使用的資源解析系統來確定的列數顯示。

src/main/res/values/integers.xml並添加:

<resources> 
    <integer name="grid_column_count">2</integer> 
</resources> 

src/main/res/values-large/integers.xml並添加:

<resources> 
    <integer name="grid_column_count">3</integer> 
</resources> 

通知的-large,這將告知這個尺寸的屏幕,上面應該利用這個備用系統資源價值。現在,在您的片段,你可以簡單的寫:

int columnCount = getResources().getInteger(R.integer.grid_column_count); 
GridLayoutManager layout = new GridLayoutManager(getActivity(), columnCount, 
     GridLayoutManager.HORIZONTAL, false); 

我提到這一點,因爲屏幕尺寸桶(該-large)可能無法確定列數的最佳方式。您可能更適合使用屏幕寬度限定符代替(例如-w600dp),如果設備旋轉(而該大小存儲桶在該場景中不更改),則會更新該寬度限定符。您可以閱讀關於資源限定符here的更多信息。

+0

謝謝!關於更新我的適配器:當我得到我的圖像按鈕的第一個圖像時,我收到警告「沒有附加適配器:跳過佈局」,但我的圖像按鈕被創建好。但後來當我嘗試向佈局添加第二個圖像按鈕時,我得到了相同的警告,同時我的應用程序崩潰給出一個nullPointerException。是否有任何明顯的事情可以導致這種情況? – Natalie

+0

@Natalie如果你不能自己解決,最好發佈一個單獨的問題,包括來自Logcat的整個堆棧跟蹤 – Karakuri

+0

非常感謝你提供關於如何獲得我的屏幕大小的建議。您的解決方案更加優雅。 – Natalie