按特定顺序添加视图并存储该顺序
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...) 您可以按您想要的顺序添加布局!重要的部分只是以良好的顺序检索它们。以上是关于按特定顺序添加视图并存储该顺序的主要内容,如果未能解决你的问题,请参考以下文章