OnItemSelectedを新たにインスタンス化されたスピナーで発射しないようにするにはどうすればよいですか?
-
23-09-2019 - |
質問
私はこれを解決するためのエレガントではない方法をいくつか考えましたが、私は何かを逃しているに違いないことを知っています。
じぶんの onItemSelected
ユーザーとのやり取りなしにすぐに発生し、これは望ましくない動作です。ユーザーが何かをする前に何かを選択するまで、UIが待ってほしい。
リスナーをセットアップしてみました onResume()
, 、それが役立つことを望んでいますが、そうではありません。
ユーザーがコントロールに触れることができるようになる前に、これを発射するのを止めるにはどうすればよいですか?
public class CMSHome extends Activity {
private Spinner spinner;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Heres my spinner ///////////////////////////////////////////
spinner = (Spinner) findViewById(R.id.spinner);
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
this, R.array.pm_list, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
};
public void onResume() {
super.onResume();
spinner.setOnItemSelectedListener(new MyOnItemSelectedListener());
}
public class MyOnItemSelectedListener implements OnItemSelectedListener {
public void onItemSelected(AdapterView<?> parent,
View view, int pos, long id) {
Intent i = new Intent(CMSHome.this, ListProjects.class);
i.putExtra("bEmpID", parent.getItemAtPosition(pos).toString());
startActivity(i);
Toast.makeText(parent.getContext(), "The pm is " +
parent.getItemAtPosition(pos).toString(), Toast.LENGTH_LONG).show();
}
public void onNothingSelected(AdapterView parent) {
// Do nothing.
}
}
}
解決
私はあなたのソリューションが機能することを期待していたでしょう - リスナーをセットアップする前にアダプターを設定した場合、選択イベントは発生しません。
そうは言っても、単純なブールフラグを使用すると、Rogue First Selectionイベントを検出して無視できます。
他のヒント
Runnablesの使用は完全に正しくありません。
使用する setSelection(position, false);
以前の最初の選択で setOnItemSelectedListener(listener)
これにより、選択されたアイテムを選択したリスナーを呼び出すアニメーションなしで選択を設定します。しかし、リスナーはnullなので、何も実行されません。その後、リスナーが割り当てられます。
したがって、この正確なシーケンスに従ってください。
Spinner s = (Spinner)Util.findViewById(view, R.id.sound, R.id.spinner);
s.setAdapter(adapter);
s.setSelection(position, false);
s.setOnItemSelectedListener(listener);
ダンダイアーの答えを参照して、登録してみてください OnSelectListener
で post(Runnable)
方法:
spinner.post(new Runnable() {
public void run() {
spinner.setOnItemSelectedListener(listener);
}
});
私のためにそれをすることで、希望する行動がついに起こりました。
この場合、リスナーが変更されたアイテムにのみ発射することも意味します。
変更するための小さなユーティリティ方法を作成しました Spinner
ユーザーに通知せずに選択:
private void setSpinnerSelectionWithoutCallingListener(final Spinner spinner, final int selection) {
final OnItemSelectedListener l = spinner.getOnItemSelectedListener();
spinner.setOnItemSelectedListener(null);
spinner.post(new Runnable() {
@Override
public void run() {
spinner.setSelection(selection);
spinner.post(new Runnable() {
@Override
public void run() {
spinner.setOnItemSelectedListener(l);
}
});
}
});
}
リスナーを無効にし、選択を変更し、その後リスナーに再執行します。
トリックは、呼び出しがUIスレッドに対して非同期であるため、連続したハンドラーの投稿でそれを行う必要があることです。
残念ながら、この問題に対して最も一般的に提案されている2つのソリューション、つまりコールバックの発生をカウントし、後でコールバックを設定するために実行可能なものを投稿することは、たとえばアクセシビリティオプションが有効になっている場合、両方とも失敗する可能性があるようです。これらの問題を回避するヘルパークラスは次のとおりです。さらに説明がコメントブロックにあります。
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.Spinner;
import android.widget.SpinnerAdapter;
/**
* Spinner Helper class that works around some common issues
* with the stock Android Spinner
*
* A Spinner will normally call it's OnItemSelectedListener
* when you use setSelection(...) in your initialization code.
* This is usually unwanted behavior, and a common work-around
* is to use spinner.post(...) with a Runnable to assign the
* OnItemSelectedListener after layout.
*
* If you do not call setSelection(...) manually, the callback
* may be called with the first item in the adapter you have
* set. The common work-around for that is to count callbacks.
*
* While these workarounds usually *seem* to work, the callback
* may still be called repeatedly for other reasons while the
* selection hasn't actually changed. This will happen for
* example, if the user has accessibility options enabled -
* which is more common than you might think as several apps
* use this for different purposes, like detecting which
* notifications are active.
*
* Ideally, your OnItemSelectedListener callback should be
* coded defensively so that no problem would occur even
* if the callback was called repeatedly with the same values
* without any user interaction, so no workarounds are needed.
*
* This class does that for you. It keeps track of the values
* you have set with the setSelection(...) methods, and
* proxies the OnItemSelectedListener callback so your callback
* only gets called if the selected item's position differs
* from the one you have set by code, or the first item if you
* did not set it.
*
* This also means that if the user actually clicks the item
* that was previously selected by code (or the first item
* if you didn't set a selection by code), the callback will
* not fire.
*
* To implement, replace current occurrences of:
*
* Spinner spinner =
* (Spinner)findViewById(R.id.xxx);
*
* with:
*
* SpinnerHelper spinner =
* new SpinnerHelper(findViewById(R.id.xxx))
*
* SpinnerHelper proxies the (my) most used calls to Spinner
* but not all of them. Should a method not be available, use:
*
* spinner.getSpinner().someMethod(...)
*
* Or just add the proxy method yourself :)
*
* (Quickly) Tested on devices from 2.3.6 through 4.2.2
*
* @author Jorrit "Chainfire" Jongma
* @license WTFPL (do whatever you want with this, nobody cares)
*/
public class SpinnerHelper implements OnItemSelectedListener {
private final Spinner spinner;
private int lastPosition = -1;
private OnItemSelectedListener proxiedItemSelectedListener = null;
public SpinnerHelper(Object spinner) {
this.spinner = (spinner != null) ? (Spinner)spinner : null;
}
public Spinner getSpinner() {
return spinner;
}
public void setSelection(int position) {
lastPosition = Math.max(-1, position);
spinner.setSelection(position);
}
public void setSelection(int position, boolean animate) {
lastPosition = Math.max(-1, position);
spinner.setSelection(position, animate);
}
public void setOnItemSelectedListener(OnItemSelectedListener listener) {
proxiedItemSelectedListener = listener;
spinner.setOnItemSelectedListener(listener == null ? null : this);
}
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (position != lastPosition) {
lastPosition = position;
if (proxiedItemSelectedListener != null) {
proxiedItemSelectedListener.onItemSelected(
parent, view, position, id
);
}
}
}
public void onNothingSelected(AdapterView<?> parent) {
if (-1 != lastPosition) {
lastPosition = -1;
if (proxiedItemSelectedListener != null) {
proxiedItemSelectedListener.onNothingSelected(
parent
);
}
}
}
public void setAdapter(SpinnerAdapter adapter) {
if (adapter.getCount() > 0) {
lastPosition = 0;
}
spinner.setAdapter(adapter);
}
public SpinnerAdapter getAdapter() { return spinner.getAdapter(); }
public int getCount() { return spinner.getCount(); }
public Object getItemAtPosition(int position) { return spinner.getItemAtPosition(position); }
public long getItemIdAtPosition(int position) { return spinner.getItemIdAtPosition(position); }
public Object getSelectedItem() { return spinner.getSelectedItem(); }
public long getSelectedItemId() { return spinner.getSelectedItemId(); }
public int getSelectedItemPosition() { return spinner.getSelectedItemPosition(); }
public void setEnabled(boolean enabled) { spinner.setEnabled(enabled); }
public boolean isEnabled() { return spinner.isEnabled(); }
}
私は望んでいないときのスピナーの発砲に多くの問題を抱えており、ここでのすべての答えは信頼できません。彼らは働きます - しかし、時々だけです。最終的には、それらが失敗するシナリオに遭遇し、コードにバグを導入します。
私のために働いたのは、最後に選択したインデックスを変数に保存し、リスナーで評価することでした。新しい選択されたインデックスと同じ場合、何もせずに戻ります。それ以外はリスナーを続けます。これを行う:
//Declare a int member variable and initialize to 0 (at the top of your class)
private int mLastSpinnerPosition = 0;
//then evaluate it in your listener
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
if(mLastSpinnerPosition == i){
return; //do nothing
}
mLastSpinnerPosition = i;
//do the rest of your code now
}
私がこれを言うとき、私を信じてください、これは断然最も信頼できるソリューションです。ハックですが、機能します!
私は同様の状況にあり、私のために働く簡単な解決策があります。
方法のようです setSelection(int position)
と setSelected(int position, boolean animate)
異なる内部実装があります。
2番目の方法を使用するとき setSelected(int position, boolean animate)
偽のアニメートフラグを使用すると、発射せずに選択を取得します onItemSelected
リスナー。
OnTouchListenerを使用して、SetOnItemSelectedListener(アクティビティ初期化の一部であるなど)と実際のユーザーインタラクションによってトリガーされるコールと、他の提案を試した後、次のことを試した後、そして以下を締めくくることを示唆するために、flesshoteを具体化するためにコードの最も少ない行でうまく機能したことがわかりました。
次のようなアクティビティ/フラグメントにブールフィールドを設定するだけです。
private Boolean spinnerTouched = false;
その後、SpinnerのSetOnItemSelectedListenerを設定する直前に、OnTouchListenerを設定します。
spinner.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
System.out.println("Real touch felt.");
spinnerTouched = true;
return false;
}
});
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
...
if (spinnerTouched){
//Do the stuff you only want triggered by real user interaction.
}
spinnerTouched = false;
spinner.setSelection(Adapter.NO_SELECTION, false);
長い間髪を引き出した後、私は自分のスピナークラスを作成しました。リスナーを適切に切断して接続する方法を追加しました。
public class SaneSpinner extends Spinner {
public SaneSpinner(Context context) {
super(context);
}
public SaneSpinner(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SaneSpinner(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
// set the ceaseFireOnItemClickEvent argument to true to avoid firing an event
public void setSelection(int position, boolean animate, boolean ceaseFireOnItemClickEvent) {
OnItemSelectedListener l = getOnItemSelectedListener();
if (ceaseFireOnItemClickEvent) {
setOnItemSelectedListener(null);
}
super.setSelection(position, animate);
if (ceaseFireOnItemClickEvent) {
setOnItemSelectedListener(l);
}
}
}
このようにXMLでそれを使用します:
<my.package.name.SaneSpinner
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/mySaneSpinner"
android:entries="@array/supportedCurrenciesFullName"
android:layout_weight="2" />
あなたがしなければならないのは、インフレ後のSanespinnerのインスタンスを取得し、次のような選択を呼び出すことです。
mMySaneSpinner.setSelection(1, true, true);
これにより、イベントは解雇されず、ユーザーの相互作用は中断されません。これにより、コードの複雑さが大幅に減少しました。これは本当にピタであるため、StockAndroidに含める必要があります。
レイアウトフェーズからの不要なイベントは、レイアウトが終了するまでリスナーを追加する場合、次のことを延期していません。
spinner.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
// Ensure you call it only once works for JELLY_BEAN and later
spinner.getViewTreeObserver().removeOnGlobalLayoutListener(this);
// add the listener
spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
// check if pos has changed
// then do your work
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
}
});
}
});
これは、Codeで選択している場合に発生します。
mSpinner.setSelection(0);
上記のステートメントの使用の代わりに
mSpinner.setSelection(0,false);//just simply do not animate it.
編集:このメソッドは、Mi AndroidバージョンMI UIでは機能しません。
私は非常に簡単な答えを得ました、それが機能することを100%確信しています:
boolean Touched=false; // this a a global variable
public void changetouchvalue()
{
Touched=true;
}
// this code is written just before onItemSelectedListener
spinner.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
System.out.println("Real touch felt.");
changetouchvalue();
return false;
}
});
//inside your spinner.SetonItemSelectedListener , you have a function named OnItemSelected iside that function write the following code
if(Touched)
{
// the code u want to do in touch event
}
これに対してはるかにエレガントなソリューションを見つけました。これには、ArrayAdapter(「Adapter」の場合)が呼び出された回数をカウントします。スピナーが1つあり、電話をかけているとしましょう。
int iCountAdapterCalls = 0;
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
this, R.array.pm_list, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
OnCreateの後にINTカウンターを宣言し、その後OnItemSelected()メソッド内に「IF」条件を設定して、ATAPTERが何回呼び出されたかを確認します。あなたの場合、あなたはそれが一度だけ電話をかけましたので:
if(iCountAdapterCalls < 1)
{
iCountAdapterCalls++;
//This section executes in onCreate, during the initialization
}
else
{
//This section corresponds to user clicks, after the initialization
}
私の小さな貢献は、上記のいくつかのバリエーションであり、それは私に何度か私に合っています。
整数変数をデフォルト値(または設定で保存された最後の使用値)として宣言します。リスナーが登録される前に、Spinner.setselection(MyDefault)を使用してその値を設定します。 OnITemSelectedでは、新しいスピナー値がさらにコードを実行する前に割り当てた値に等しいかどうかを確認します。
これには、ユーザーが同じ値を再度選択した場合、コードを実行しないという追加の利点があります。
同じ問題を抱えた後、私はタグを使用してこのソリューションに来ました。その背後にあるアイデアは簡単です。スピナーがプログラムで変更されるたびに、タグが選択された位置を反映していることを確認してください。リスナーでは、選択した位置がタグに等しいかどうかを確認します。もしそうなら、スピナーの選択はプログラムで変更されました。
以下は私の新しい「スピナープロキシ」クラスです。
package com.samplepackage;
import com.samplepackage.R;
import android.widget.Spinner;
public class SpinnerFixed {
private Spinner mSpinner;
public SpinnerFixed(View spinner) {
mSpinner = (Spinner)spinner;
mSpinner.setTag(R.id.spinner_pos, -2);
}
public boolean isUiTriggered() {
int tag = ((Integer)mSpinner.getTag(R.id.spinner_pos)).intValue();
int pos = mSpinner.getSelectedItemPosition();
mSpinner.setTag(R.id.spinner_pos, pos);
return (tag != -2 && tag != pos);
}
public void setSelection(int position) {
mSpinner.setTag(R.id.spinner_pos, position);
mSpinner.setSelection(position);
}
public void setSelection(int position, boolean animate) {
mSpinner.setTag(R.id.spinner_pos, position);
mSpinner.setSelection(position, animate);
}
// If you need to proxy more methods, use "Generate Delegate Methods"
// from the context menu in Eclipse.
}
また、タグのセットアップを備えたXMLファイルも必要です Values
ディレクトリ。ファイルに名前を付けました spinner_tag.xml
, 、しかし、それはあなた次第です。このように見えます:
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<item name="spinner_pos" type="id" />
</resources>
次に交換します
Spinner myspinner;
...
myspinner = (Spinner)findViewById(R.id.myspinner);
のコードで
SpinnerFixed myspinner;
...
myspinner = new SpinnerFixed(findViewById(R.id.myspinner));
そして、あなたのハンドラーをこのように見せます:
myspinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (myspinner.isUiTriggered()) {
// Code you want to execute only on UI selects of the spinner
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
関数 isUiTriggered()
スピナーがユーザーによって変更された場合にのみ、trueを返します。この関数には副作用があることに注意してください - タグが設定されるため、同じリスナーコールの2回目の呼び出しは常に戻ります false
.
このラッパーは、レイアウト作成中にリスナーが呼び出されるという問題を処理します。
楽しんでください、ジェンズ。
私のために何もうまくいきませんでした、そして私は私の見解に1つ以上のスピナーを持っているので(そして、ブールマップを保持している私見はやり過ぎです)、私はタグを使用してクリックをカウントします:
spinner.setTag(0);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
Integer selections = (Integer) parent.getTag();
if (selections > 0) {
// real selection
}
parent.setTag(++selections); // (or even just '1')
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
すでにたくさんの答えがあります、ここに私のものがあります。
私は拡張します AppCompatSpinner
メソッドを追加します pgmSetSelection(int pos)
これにより、選択コールバックをトリガーせずにプログラムの選択設定が可能になります。これをrxjavaでコーディングして、選択イベントが介して配信されるようにしました Observable
.
package com.controlj.view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.AdapterView;
import io.reactivex.Observable;
/**
* Created by clyde on 22/11/17.
*/
public class FilteredSpinner extends android.support.v7.widget.AppCompatSpinner {
private int lastSelection = INVALID_POSITION;
public void pgmSetSelection(int i) {
lastSelection = i;
setSelection(i);
}
/**
* Observe item selections within this spinner. Events will not be delivered if they were triggered
* by a call to setSelection(). Selection of nothing will return an event equal to INVALID_POSITION
*
* @return an Observable delivering selection events
*/
public Observable<Integer> observeSelections() {
return Observable.create(emitter -> {
setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
if(i != lastSelection) {
lastSelection = i;
emitter.onNext(i);
}
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
onItemSelected(adapterView, null, INVALID_POSITION, 0);
}
});
});
}
public FilteredSpinner(Context context) {
super(context);
}
public FilteredSpinner(Context context, int mode) {
super(context, mode);
}
public FilteredSpinner(Context context, AttributeSet attrs) {
super(context, attrs);
}
public FilteredSpinner(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public FilteredSpinner(Context context, AttributeSet attrs, int defStyleAttr, int mode) {
super(context, attrs, defStyleAttr, mode);
}
}
呼び出された使用の例 onCreateView()
で Fragment
例えば:
mySpinner = view.findViewById(R.id.history);
mySpinner.observeSelections()
.subscribe(this::setSelection);
どこ setSelection()
このように見える囲いビューの方法であり、ユーザー選択イベントからの両方と呼ばれます。 Observable
また、他の場所ではプログラムでも、選択の処理のロジックは両方の選択方法に共通しています。
private void setSelection(int position) {
if(adapter.isEmpty())
position = INVALID_POSITION;
else if(position >= adapter.getCount())
position = adapter.getCount() - 1;
MyData result = null;
mySpinner.pgmSetSelection(position);
if(position != INVALID_POSITION) {
result = adapter.getItem(position);
}
display(result); // show the selected item somewhere
}
私は電話しようとします
spinner.setOnItemSelectedListener(new MyOnItemSelectedListener());
SetAdapter()に電話した後。また、アダプターの前に電話をかけてみてください。
サブクラス化に合うソリューションが常にあり、ブールフラグをOverriden SetAdapterメソッドにラップしてイベントをスキップできます。
ブールフラグやカウンターを備えた解決策は私を助けませんでした。
私はサブクラス化しました android.widget.Spinner
そして小さな追加をしました。関連する部分は以下にあります。このソリューションは私のために働きました。
private void setHandleOnItemSelected()
{
final StackTraceElement [] elements = Thread.currentThread().getStackTrace();
for (int index = 1; index < elements.length; index++)
{
handleOnItemSelected = elements[index].toString().indexOf("PerformClick") != -1; //$NON-NLS-1$
if (handleOnItemSelected)
{
break;
}
}
}
@Override
public void setSelection(int position, boolean animate)
{
super.setSelection(position, animate);
setHandleOnItemSelected();
}
@Override
public void setSelection(int position)
{
super.setSelection(position);
setHandleOnItemSelected();
}
public boolean shouldHandleOnItemSelected()
{
return handleOnItemSelected;
}
これもエレガントなソリューションではありません。実際、それはむしろrube-goldbergですが、うまくいくようです。アレイアダプターを拡張し、GetDropDownViewをオーバーライドすることにより、スピナーが少なくとも1回使用されていることを確認します。新しいGetDropDownViewメソッドには、ドロップダウンメニューが少なくとも1回使用されていることを示すように設定されているブールフラグがあります。フラグが設定されるまで、リスナーへの呼び出しを無視します。
mainactivity.oncreate():
ActionBar ab = getActionBar();
ab.setDisplayShowTitleEnabled(false);
ab.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
ab.setListNavigationCallbacks(null, null);
ArrayList<String> abList = new ArrayList<String>();
abList.add("line 1");
...
ArAd abAdapt = new ArAd (this
, android.R.layout.simple_list_item_1
, android.R.id.text1, abList);
ab.setListNavigationCallbacks(abAdapt, MainActivity.this);
Overridenアレイアダプター:
private static boolean viewed = false;
private class ArAd extends ArrayAdapter<String> {
private ArAd(Activity a
, int layoutId, int resId, ArrayList<String> list) {
super(a, layoutId, resId, list);
viewed = false;
}
@Override
public View getDropDownView(int position, View convertView,
ViewGroup parent) {
viewed = true;
return super.getDropDownView(position, convertView, parent);
}
}
修正されたリスナー:
@Override
public boolean onNavigationItemSelected(
int itemPosition, long itemId) {
if (viewed) {
...
}
return false;
}
その場でアクティビティを再作成する必要がある場合:テーマの変更、単純なフラグ/カウンターは機能しません
onuserInteraction()関数を使用してユーザーアクティビティを検出し、
私は持っている 終わり 最も簡単な方法で:
private AdapterView.OnItemSelectedListener listener;
private Spinner spinner;
oncreate();
spinner = (Spinner) findViewById(R.id.spinner);
listener = new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int position, long l) {
Log.i("H - Spinner selected position", position);
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
};
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
spinner.setOnItemSelectedListener(listener);
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
終わり
if () {
spinner.setSelection(0);// No reaction to create spinner !!!
} else {
spinner.setSelection(intPosition);
}
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (position > 0) {
// real selection
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
コードに照らされていた2の幅に2を掛けるだけで私の問題の解決策を得ることができました:
CGFloat width = [ScrollingLabel.text sizeWithFont:ScrollingLabel.font].width;
ScrollingLabel.frame = CGRectMake(1024,720,width,45);
. 使用する必要があります mSpinner
ビューホルダーでは、旗 mOldPosition
匿名の内部クラスに設定されています。
mSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
int mOldPosition = mSpinner.getSelectedItemPosition();
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long l) {
if (mOldPosition != position) {
mOldPosition = position;
//Do something
}
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
//Do something
}
});
あなたは lingua zptとzope.i18nmessageIdのプラグインを提供し、I18ndudeのすべての機能を提供しますが、適度にアクティブなオープンソースコミュニティ。
プロジェクトでBabelを使用するには、設定する必要があります。 babelコマンドを使用するには、setup.pyコマンドとして機能します。例えばpython yourpackage/setup.py extract_messages
lingua
eggを依存関係として入手可能にしても、Setup.pyのmessage_extractors
構造体のプラグインのプラグインのプラグインBabelソースファイルからI18Nメッセージを抽出する方法:
...
from babel.messages import frontend as babel
...
setup(...
setup_requires=['lingua'],
cmdclass = dict(
compile_catalog=babel.compile_catalog,
extract_messages=babel.extract_messages,
init_catalog=babel.init_catalog,
update_catalog=babel.update_catalog,
),
message_extractors = {
'path/in/package': [
('**.py', 'lingua_python', None),
('**/templates/**.pt', 'lingua_xml', None),
],
},
...
)
.
Setup.pyスクリプトは、実際にBabelをインポートできる場合にのみ機能するため、Setup_Requires依存関係としてBabelを含めることはできません。 CMDClassエントリのシムを作成することで、これを回避できますが、まだこれを試してみません。今のところ、VirtualenvまたはGliverallyにBabel Eggをインストールするだけです。
--mapping-file
エントリの代わりにmessage_extractors
CLIオプションを使用したい場合、そのオプションは[method fileglob]
ヘッダーを持つINIスタイルのファイル形式を想定しています。
[lingua_python **.py]
[lingua_xml **/templates/**.pt]
.
各セクションにはextractor関数に渡すオプションを含めることができます(各option = value
行は、それに渡されたオプションの区切りのオプションのキー値のペアになります)、LINGUA_ *メソッドはオプションを取ります。
コマンドラインで言及した入力DIR、またはsetup.py grefodicetagcodeオプションに記載されている各パッケージごとに抽出プログラムを使用します。
mod_rewrite
に頼ることなくこれを行うことができるはずです。
RedirectMatch ^/$ http://www.yourdomain.com/hold/
.
(最初のRewriteRule
はRewriteBase /
を想定しているため、疑うと思われる疑いがあります。私は混乱を避けるためにRewriteBase
を完全に避けたままにします。)
私は投稿で遅すぎるかもしれませんが、Androidデータバインディングライブラリを使用してこれを達成することができました Androidデータビンディング 。選択されたアイテムが変更されるまでリスナーが呼び出されないようにカスタムバインディングを作成したので、ユーザーが同じ位置を繰り返し選択している場合でも、イベントが起動されません。
レイアウトXMLファイル
<layout>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/activity_vertical_margin"
xmlns:app="http://schemas.android.com/apk/res-auto">
<Spinner
android:id="@+id/spinner"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:spinnerMode="dropdown"
android:layout_below="@id/member_img"
android:layout_marginTop="@dimen/activity_vertical_margin"
android:background="@drawable/member_btn"
android:padding="@dimen/activity_horizontal_margin"
android:layout_marginStart="@dimen/activity_horizontal_margin"
android:textColor="@color/colorAccent"
app:position="@{0}"
/>
</RelativeLayout>
</layout>
app:position
選択する位置を渡す場所です。
カスタムバインディング
@BindingAdapter(value={ "position"}, requireAll=false)
public static void setSpinnerAdapter(Spinner spinner, int selected)
{
final int [] selectedposition= new int[1];
selectedposition[0]=selected;
// custom adapter or you can set default adapter
CustomSpinnerAdapter customSpinnerAdapter = new CustomSpinnerAdapter(spinner.getContext(), <arraylist you want to add to spinner>);
spinner.setAdapter(customSpinnerAdapter);
spinner.setSelection(selected,false);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
String item = parent.getItemAtPosition(position).toString();
if( position!=selectedposition[0]) {
selectedposition[0]=position;
// do your stuff here
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
カスタムデータバインディングの詳細については、こちらをご覧ください Androidカスタムセッター
ノート
Gradleファイルでデータバインディングを有効にすることを忘れないでください
android { .... dataBinding { enabled = true } }
レイアウトファイルをに含めます
<layout>
タグ
mYear.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View arg1, int item, long arg3) {
if (mYearSpinnerAdapter.isEnabled(item)) {
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});