私はTextViewsをプログラムでforループに追加し、それらをArrayListに追加しています。
どうすれば使えTextView.setId(int id)
ますか?他のIDと競合しないように、どの整数IDを思い付くのですか?
私はTextViewsをプログラムでforループに追加し、それらをArrayListに追加しています。
どうすれば使えTextView.setId(int id)
ますか?他のIDと競合しないように、どの整数IDを思い付くのですか?
APIレベル17以降から、次の呼び出しを行うことができます:View.generateViewId()
次に、View.setId(int)を使用します。
アプリがAPIレベル17より低いターゲットになっている場合は、ViewCompat.generateViewId()を使用します
xmlリソースファイルを使用してクラスで後で使用するIDを定義R.id
し、AndroidSDKにコンパイル時に実際の一意の値を設定させることができます。
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
。あなたはアンドロイドのサンプルコードで正確な例を見ることができます。
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++;
}
(これはdilettanteの答えへのコメントでしたが、長すぎました... hehe)
もちろん、ここではスタティックは必要ありません。静的ではなく、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()
fromを使用できます。ViewCompat
View
//Will assign a unique ID
myView.id = ViewCompat.generateViewId()
ハッピーコーディング!
@phantomlimbの答えへの単なる追加、
View.generateViewId()
APIレベル>=17が必要ですが、この
ツールはすべてのAPIと互換性があります。
現在の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();
}
}
}
ビューIDフォームAPI17を動的に生成するには、
での使用に適した値を生成しますsetId(int)
。この値は、ビルド時にaaptforによって生成されたID値と衝突しませんR.id
。
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();
}