按特定顺序添加视图并存储该顺序

Posted

技术标签:

【中文标题】按特定顺序添加视图并存储该顺序【英文标题】: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 然后再次添加它,它将按照我的意愿放置在最后一个插槽中,但是当我重新创建活动时,它会回到第一个位置,因为由于代码获取按其顺序读取,它将按初始顺序添加视图。

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

【问题讨论】:

【参考方案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...) 您可以按您想要的顺序添加布局!重要的部分只是以良好的顺序检索它们。

以上是关于按特定顺序添加视图并存储该顺序的主要内容,如果未能解决你的问题,请参考以下文章

couchdb 按值、限制和按时间顺序获取

Symfony按特定字段的内容顺序排列

如何按顺序将子视图添加到 UIScrollView

iOS 分类:按顺序添加视图

如何使用标志在 Drupal 视图中为节点提供特定的放置顺序

如何通过按图像保存在 NSArray 中的顺序单击缩略图来在滚动视图中打开图像?