我在 for 循环中以编程方式添加 TextViews 并将它们添加到 ArrayList。
我该如何使用TextView.setId(int id)
?我想出什么整数 ID 才不会与其他 ID 冲突?
我在 for 循环中以编程方式添加 TextViews 并将它们添加到 ArrayList。
我该如何使用TextView.setId(int id)
?我想出什么整数 ID 才不会与其他 ID 冲突?
从 API 级别 17 及以上,您可以调用:View.generateViewId()
然后使用View.setId(int)。
如果您的应用程序目标低于 API 级别 17,请使用ViewCompat.generateViewId()
您可以R.id
使用 xml 资源文件定义稍后在课堂上使用的 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);
根据View
文档
标识符在此视图的层次结构中不必是唯一的。标识符应该是一个正数。
所以你可以使用任何你喜欢的正整数,但在这种情况下,可能会有一些具有等效 ID 的视图。如果您想在层次结构中搜索某些视图,setTag
使用某些关键对象调用可能会很方便。
您也可以ids.xml
在res/values
. 您可以在 android 的示例代码中看到一个确切的示例。
samples/ApiDemos/src/com/example/android/apis/RadioGroup1.java
samples/ApiDemp/res/values/ids.xml
从 API 17 开始,View
该类有一个静态方法 generateViewId()
,它将
生成适合在 setId(int) 中使用的值
这对我有用:
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++;
}
(这是对业余爱好者回答的评论,但它太长了......呵呵)
当然,这里不需要静态。您可以使用 SharedPreferences 来保存,而不是静态的。无论哪种方式,原因都是为了保存当前的进度,以便它对于复杂的布局不会太慢。因为,其实用过一次以后,会比较快。但是,我认为这不是一个好方法,因为如果您必须再次重建屏幕(例如再次onCreate
调用),那么您可能无论如何都想从头开始,消除对静态的需要。因此,只需将其设为实例变量而不是静态变量。
这是一个运行速度更快且可能更易于阅读的较小版本:
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
编辑/修复:刚刚意识到我完全搞砸了保存。我一定是喝醉了。
'Compat' 库现在还支持generateViewId()
17 之前的 API 级别的方法。
只要确保使用的Compat
库版本是27.1.0+
例如,在您的build.gradle
文件中,输入:
implementation 'com.android.support:appcompat-v7:27.1.1
然后你可以简单地使用generateViewId()
fromViewCompat
类而不是View
类,如下所示:
//Will assign a unique ID
myView.id = ViewCompat.generateViewId()
快乐编码!
只是对@phantomlimb 答案的补充,
虽然View.generateViewId()
要求 API 级别 >= 17,
但此工具与所有 API 兼容。
根据当前的 API Level
决定天气是否使用系统 API。
所以你可以同时使用ViewIdGenerator.generateViewId()
andView.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();
}
}
}
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();
}
}
}
受@dilettante 回答的启发,这是我在 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
}
我用:
public synchronized int generateViewId() {
Random rand = new Random();
int id;
while (findViewById(id = rand.nextInt(Integer.MAX_VALUE) + 1) != null);
return id;
}
通过使用随机数,我总是很有可能在第一次尝试时获得唯一 ID。
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();
}