【问题标题】:Adding views in a specific order and storing that order按特定顺序添加视图并存储该顺序
【发布时间】:2016-08-25 04:15:04
【问题描述】:

我有一个“添加”按钮和一个带有 6 个插槽的 GridLayout,当我单击“添加”按钮时,view1 被添加到网格布局中,我再次单击“添加”按钮 view2 被添加,依此类推.

 if (!theLayout1.isShown()) {
      Grid.addView(theLayout1);
 } else if (!theLayout2.isShown()) {
      Grid.addView(theLayout2);
 } else if (!theLayout3.isShown() ) {
      Grid.addView(theLayout3);
 } ..... // this goes on

添加视图后,我会检查其文本是否已添加到 sharedPrefs 中,以便在重新创建活动时自动添加它们

if (prefs.getString("text4", null) != null) {
    Grid.addView(theLayout4);
}

if (prefs.getString("text5", null) != null) {
    Grid.addView(theLayout5);
}
// each view has one EditText

我的问题是,如果我删除 view1 然后再次添加它,它将按照我的意愿放置在最后一个插槽中,但是当我重新创建活动时,它会回到第一个位置,因为由于代码获取按其顺序读取,它将按初始顺序添加视图。

我想在按照完成活动之前的顺序重新创建活动时添加视图,这可能有一个简单的逻辑解决方案,或者我只是非常错误地解决了这个问题,无论如何,需要帮助!

【问题讨论】:

    标签: java android android-layout logic


    【解决方案1】:

    首先,您可以将视图标签“或任何您标记它们的”存储在具有标签和视图所在位置的数据结构中,然后将代码存储在 SharedPreferences 中。

    public void savePreferences() {
            SharedPreferences mPrefs = PreferenceManager.getDefaultSharedPreferences(activity);
            SharedPreferences.Editor prefsEditor = mPrefs.edit();
            Gson gson = new Gson();
            String json = gson.toJson(dataStructure, new TypeToken<DataStructure>() {
            }.getType());
            prefsEditor.putString("ordering", json);
            prefsEditor.commit();
        }
    
        public static DataStructure loadPreferences() {
            SharedPreferences mPrefs = PreferenceManager.getDefaultSharedPreferences(activity);
            Gson gson = new Gson();
            String json = mPrefs.getString("ordering", "");
            if (!json.equals("")) {
                return (DataStructure) gson.fromJson(json, new TypeToken<DataStructure>() {
                }.getType());
            } else {
                return new DataStructure();
            }
        }
    

    然后当你检索上面提到的数据结构时,你可以使用以下代码根据它们的位置对结果进行排序:

    Arrays.sort(dataStructure , new Comparator<DataStructureElement>() {
        @Override
        public int compare(DataStructureElement o1, DataStructureElement o2) {
            return Integer.compare(o1.position, o2.position);
        }
    });
    

    然后在dataStructure中遍历排序后的结果,将视图按正常顺序添加到GridLayout中。

    【讨论】:

      【解决方案2】:

      问题(至少从我从您的问题中了解到的)是您没有在首选项中保存某种指示视图在其父视图中的位置。现在,第一次添加与删除后再次添加视图之间没有区别,或者在插槽 1 与插槽 5 中添加视图(例如)之间没有区别。处理此问题的一种方法是在每个插槽的首选项中输入一个条目,然后在这些插槽首选项中保存视图指示器:

      例如:

      // the base of the slot keys, there will be 6 of them from 1 to 6 inclusive
      private static final String KEY_SLOT = "key_slot";
      
      // when adding the view for slot 2 you'll save in preferences text2 it's indicator
      prefEditor.putString(KEY_SLOT + position, text2); // position will be 2, the indicator of the slot in your layout
      
      // when you delete the view from a slot, nullify it's slot preferences
      // for example deleting the slot 3(child 3 in the layout)
      prefEditor.putString(KEY_SLOT + position, null); position will be 3
      

      当您重新创建活动时,请查看所有 SLOT 首选项并查看它们持有哪些值。如果您的布局允许有孔(例如没有插槽 2 的视图,但有插槽 1 和 3 的视图),它们可能为 null,或者它们可以保存您的 text* 变量之一,指示应将哪个视图放置在该插槽中:

      // in the activity:
      // iterate over all the SLOT preferences
      for (int i = 1; i <= 6; i++) {
         String text = prefs.getString(KEY_SLOT + i, null);
         // if text is null there is no view stored for this slot
         // keep in mind that you need to add some sort of empty widget to act as a child 
         // or modify the LayoutParams of the other children to take in consideration the empty space
         // OR
         // if text is one of your values, like text1, text2 etc
         // then you know that at slot i you need to place the view corresponding to the text value
      }
      

      【讨论】:

        【解决方案3】:

        这归结为将项目插入到排序数组中。有一种方法addView(View child, int index) 可以将视图添加到您想要使用的所需位置。您需要遍历当前添加的孩子并找到插入新孩子的正确索引。如果在添加之前使用其值标记每个视图,则可以查看标记以确定该索引的位置。

        private void insertView(View theLayoutN, int n) {
            // tag the new view with its value
            theLayoutN.setTag(Integer.valueOf(n));
        
            // iterate over the views currently in the grid, keeping track
            // of the desired insertion index
            int insertionIndex = 0;
            final int childCount = grid.getChildCount();
            for (int i = 0; i < childCount; i++) {
                // get the child currently at index i
                View child = grid.getChildAt(i);
        
                // retrieve its tag, which is its value
                int childN = ((Integer) child.getTag()).intValue();
        
                // if the child's value is greater than the value of the
                // one we're inserting, then we have found the insertionIndex
                if (childN > n) {
                    break;
                }
        
                // increment the insertionIndex
                insertionIndex++;
            }
        
            grid.addView(theLayoutN, insertionIndex);
        }
        

        然后,当你需要插入一个布局时,你可以这样做:

        if (!theLayout1.isShown()) {
            insertView(theLayout1, 1);
        } else if (!theLayout2.isShown()) {
            insertView(theLayout2, 2);
        } else if (!theLayout3.isShown()) {
            insertView(theLayout3, 3);
        }
        

        这应该确保您的视图始终处于正确的顺序。它可以通过实现二分搜索进一步优化,但如果你有这么多视图,你还是应该使用 ListView。

        但是,您可能需要完全重新考虑这种架构,因为您有很多冗余代码,可以通过循环或数据结构进行简化。或者,您可以随时添加所有视图,当您想隐藏一个视图时调用theLayout.setVisibility(View.GONE),当您想显示它时调用theLayout.setVisibility(View.VISIBLE)

        【讨论】:

        • 我在删除视图后尝试添加视图时得到一个 NullPointer:java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.Integer.intValue()' on a null object reference
        • 表示这个View没有设置标签,可能是因为你直接把那个View添加到了容器中,而不是使用insertView
        • 我确实使用过insertView
        • 在没有设置标签的情况下,视图以某种方式被添加到父级。除了这些布局之外,您是否在网格中放置了任何视图?如果是这样,如果标签为空(或不是整数),则需要跳过它。
        • 好的,这样它不会崩溃,但仍然无法按预期工作。如果我添加 3 个视图,然后删除第一个,然后重新添加,它会进入第一个位置而不是最后一个位置,我需要在删除视图后刷新位置
        【解决方案4】:

        我会通过使用 JsonArray 来处理这样的事情

        每当您添加视图时,将该文本添加到 json 数组中,然后将其作为字符串存储在您的共享首选项中。

        jsonarray.toString()
        

        您可以在删除或添加视图时轻松添加和删除项目。这也有助于您只拥有一个共享偏好并防止使用不同的共享偏好。

        SharedPreferences sf = .....
        String txt=sf.getString("YOUR_KEY","");
        JsonArray myViewArray=new JsonArray(txt);
        for(int i=0;i<myViewArray.length();i++){
           // ADD VIEW HERE
        }
        

        【讨论】:

          【解决方案5】:

          您应该将名称存储为布局名称 + 计数器。前任 : 布局1、布局2、布局3……

          当你想按顺序获取它们时,你只需要循环直到你没有任何东西可以检索:

                  int i = 1;
                  String valueStored = null;
                  do {
                      String key = "layout" + i; // layout1, layout2, layout3...
                      SharedPreferences preferences = activity.getSharedPreferences(key, 0);
                      valueStored = preferences.getString(key, null);
          
                      // View  v = getViewByName(valueStored) get the view by the name retrieved from the shared pref
                      //Grid.addView(view);
                  } while (valueStored != null); // stop when there is nothing more to get
          

          希望对你有帮助!

          【讨论】:

          • 好的,那不会在我订购的 (int) 中添加布局吗? (layout1 然后 layout2 然后 layout 3 然后 layout4...)
          • 您可以按您想要的顺序添加布局!重要的部分只是以良好的顺序检索它们。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-10-16
          • 2020-10-28
          • 2016-08-23
          • 1970-01-01
          • 2012-04-19
          相关资源
          最近更新 更多