我在for循环中以编程方式添加TextViews,并将它们添加到数组列表中。
我如何使用TextView。setId (int id) ?我要用什么样的整数ID才能不与其他ID冲突?
我在for循环中以编程方式添加TextViews,并将它们添加到数组列表中。
我如何使用TextView。setId (int id) ?我要用什么样的整数ID才能不与其他ID冲突?
根据查看文档
标识符在这个视图的层次结构中不必是唯一的。标识符应该是一个正数。
你可以使用任何你喜欢的正整数,但在这种情况下,可以有一些具有等效id的视图。如果你想在层次结构中搜索某个视图,调用带有一些关键对象的setTag可能会很方便。
你也可以在res/values中定义ids.xml。你可以在android的示例代码中看到一个确切的例子。
samples/ApiDemos/src/com/example/android/apis/RadioGroup1.java
samples/ApiDemp/res/values/ids.xml
这对我来说很管用:
static int id = 1;
// Returns a valid id that isn't in use
public int findId(){
View v = findViewById(id);
while (v != null){
v = findViewById(++id);
}
return id++;
}
(这是对业余爱好者的回答的评论,但它太长了…呵呵)
Of course a static is not needed here. You could use SharedPreferences to save, instead of static. Either way, the reason is to save the current progress so that its not too slow for complicated layouts. Because, in fact, after its used once, it will be rather fast later. However, I dont feel this is a good way to do it because if you have to rebuild your screen again (say onCreate gets called again), then you probably want to start over from the beginning anyhow, eliminating the need for static. Therefore, just make it an instance variable instead of static.
下面是一个更小的版本,运行速度更快,可能更容易阅读:
int fID = 0;
public int findUnusedId() {
while( findViewById(++fID) != null );
return fID;
}
上述函数应该足够了。因为,据我所知,android生成的id有数十亿个,所以这可能会第一次返回1,而且总是很快。 因为,它实际上不会遍历已使用的id来查找未使用的id。但是,如果它确实找到了一个使用的ID,那么循环就在那里。
然而,如果你仍然希望在后续重新创建应用程序之间保存进度,并希望避免使用静态。这是SharedPreferences版本:
SharedPreferences sp = getSharedPreferences("your_pref_name", MODE_PRIVATE);
public int findUnusedId() {
int fID = sp.getInt("find_unused_id", 0);
while( findViewById(++fID) != null );
SharedPreferences.Editor spe = sp.edit();
spe.putInt("find_unused_id", fID);
spe.commit();
return fID;
}
这个类似问题的答案应该告诉你你需要知道的关于android id的一切:https://stackoverflow.com/a/13241629/693927
编辑/修复:刚刚意识到我完全搞砸了保存。我一定是喝醉了。
从API级别17及以上,你可以调用:
然后使用View.setId(int)。
如果你的应用程序的目标低于API级别17,使用viewcompat.com generateviewid ()
为了动态生成视图Id表单API 17使用
generateViewId ()
这将生成一个适合在setId(int)中使用的值。该值不会与aapt在构建时为r.d ID生成的ID值冲突。
只是对@phantomlimb的答案的补充,
而View.generateViewId()要求API级别>= 17, 该工具与所有API兼容。
根据现时的空气污染指数, 它决定天气是否使用系统API。
所以你可以使用ViewIdGenerator.generateViewId()和View.generateViewId() 同样的时间,不用担心得到相同的id
import java.util.concurrent.atomic.AtomicInteger;
import android.annotation.SuppressLint;
import android.os.Build;
import android.view.View;
/**
* {@link View#generateViewId()}要求API Level >= 17,而本工具类可兼容所有API Level
* <p>
* 自动判断当前API Level,并优先调用{@link View#generateViewId()},即使本工具类与{@link View#generateViewId()}
* 混用,也能保证生成的Id唯一
* <p>
* =============
* <p>
* while {@link View#generateViewId()} require API Level >= 17, this tool is compatibe with all API.
* <p>
* according to current API Level, it decide weather using system API or not.<br>
* so you can use {@link ViewIdGenerator#generateViewId()} and {@link View#generateViewId()} in the
* same time and don't worry about getting same id
*
* @author fantouchx@gmail.com
*/
public class ViewIdGenerator {
private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);
@SuppressLint("NewApi")
public static int generateViewId() {
if (Build.VERSION.SDK_INT < 17) {
for (;;) {
final int result = sNextGeneratedId.get();
// aapt-generated IDs have the high byte nonzero; clamp to the range under that.
int newValue = result + 1;
if (newValue > 0x00FFFFFF)
newValue = 1; // Roll over to 1, not 0.
if (sNextGeneratedId.compareAndSet(result, newValue)) {
return result;
}
}
} else {
return View.generateViewId();
}
}
}
您可以使用xml资源文件定义稍后将在r.d ID类中使用的ID,并让Android SDK在编译时设置实际的惟一值。
res/values/ids.xml
<item name="my_edit_text_1" type="id"/>
<item name="my_button_1" type="id"/>
<item name="my_time_picker_1" type="id"/>
在代码中使用它:
myEditTextView.setId(R.id.my_edit_text_1);
int fID;
do {
fID = Tools.generateViewId();
} while (findViewById(fID) != null);
view.setId(fID);
...
public class Tools {
private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);
public static int generateViewId() {
if (Build.VERSION.SDK_INT < 17) {
for (;;) {
final int result = sNextGeneratedId.get();
int newValue = result + 1;
if (newValue > 0x00FFFFFF)
newValue = 1; // Roll over to 1, not 0.
if (sNextGeneratedId.compareAndSet(result, newValue)) {
return result;
}
}
} else {
return View.generateViewId();
}
}
}
public String TAG() {
return this.getClass().getSimpleName();
}
private AtomicInteger lastFldId = null;
public int generateViewId(){
if(lastFldId == null) {
int maxFld = 0;
String fldName = "";
Field[] flds = R.id.class.getDeclaredFields();
R.id inst = new R.id();
for (int i = 0; i < flds.length; i++) {
Field fld = flds[i];
try {
int value = fld.getInt(inst);
if (value > maxFld) {
maxFld = value;
fldName = fld.getName();
}
} catch (IllegalAccessException e) {
Log.e(TAG(), "error getting value for \'"+ fld.getName() + "\' " + e.toString());
}
}
Log.d(TAG(), "maxId="+maxFld +" name="+fldName);
lastFldId = new AtomicInteger(maxFld);
}
return lastFldId.addAndGet(1);
}
我的选择:
// Method that could us an unique id
int getUniqueId(){
return (int)
SystemClock.currentThreadTimeMillis();
}
Compat库现在还支持API级别之前的generateViewId()方法。
只要确保使用27.1.0以上版本的Compat库即可
例如,在您的构建中。Gradle文件,放入:
实现“com.android.support: appcompat-v7:27.1.1
然后你可以简单地使用来自ViewCompat类的generateViewId()而不是View类,如下所示:
//将分配唯一的ID myView。id = ViewCompat.generateViewId()
编码愉快!
受到@dilettante answer的启发,下面是我在kotlin中作为扩展函数的解决方案:
/* sets a valid id that isn't in use */
fun View.findAndSetFirstValidId() {
var i: Int
do {
i = Random.nextInt()
} while (findViewById<View>(i) != null)
id = i
}