Android 進行状況バー付きのドロップダウンリスト(スピナー)

読者の皆さん、ご挨拶!



AndroidでSpinnerと呼ばれるドロップダウンリストにデータを読み込む際に、プログレスバー(「無限の円」)を表示する方法についての短いエッセイを紹介します。

これは、Webサービスを操作するための小さなユーティリティを開発するときに必要になりました。 特定の計算のパラメーターは、中央サーバーに保存されます。 .NET Webサービスは、さまざまな長さ(2〜50要素)の配列の形式で、可能なパラメーターのリストを提供します。 これらのパラメーターを表示するために、ドロップダウンリストが選択されました。 予想どおり、リストの初期化は非同期的に行われます。 また、データの読み込み中に、何も進行せずに空の静的要素を見るのは退屈で退屈で一般的です。





目標そのもの



標準のスピナーは次のようになります。



少し改良した後、次のようなものが得られます(CustomSpinner):





「塩とは何ですか!?」-あなたは尋ねますか? そして、塩は中間状態にあります(データの読み込み):





軽いトピック:







この効果を得るには、2つの方法があります。

1スピナーから継承。 onDraw()および、場合によっては他のメソッドをオーバーライドします。 状態処理の実装(ロード/ロード)

2レイアウトから継承。 スピナーとProgressBarを配置します。 要件に従ってコントロールの作業を整理します。



最初の方法の方がおそらく正しいでしょう。 しかし、私がそれを踏むたびに、私は例外に遭遇し、アプリケーションがクラッシュしました。 私は長い間Androidを知っていましたが、onDraw()メソッドで何をする必要があるかをまだ理解していないことを正直に認めています。 私は、ソースをいじりたくはありませんが、時には役に立つかもしれません。 一般に、このパスは終了したため、開始せずにのみ。



2番目の方法は、ネットワークでより詳細に説明されています。 私はそれを素早く自然に歩きました。 そして彼はそのようでした...



XMLレイアウト



まず、新しいコントロール(custom_spinner.xml)を「スケッチ」する必要があります。 複雑なことは何もありません-ルートレイアウトと2つの娘要素(スピナーとプログレスバー)。 RelativeLayoutはこれに適しています。 私はこのようになった:



<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" > <Spinner android:id="@+id/spinner" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerInParent="true" /> <ProgressBar android:id="@+id/progress" style="@android:style/Widget.ProgressBar.Small" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" /> </RelativeLayout>
      
      







CustomSpinnerクラス



コントロールを使用するには、CustomSpinnerクラスを実装する必要があります。 RelativeLayoutから継承したクラスを作成します。



 public class CustomSpinner extends RelativeLayout { Context context; Spinner spinner; ProgressBar progress; public CustomSpinner(Context c, AttributeSet attrs) { super(c, attrs); this.context = c; //        custom_spinner.xml LayoutInflater.from(context).inflate(R.layout.custom_spinner, this, true); initViews(); } //        private void initViews() { spinner = (Spinner) findViewById(R.id.spinner); progress = (ProgressBar) findViewById(R.id.progress); } }
      
      







状態管理



元の目標(データの読み込み時に進行状況バーを表示)を達成するために、CustomSpinnerクラスを変更します。



 public class CustomSpinner extends RelativeLayout { Context context; Spinner spinner; ProgressBar progress; ArrayAdapter<String> emptyAdapter; public CustomSpinner(Context c, AttributeSet attrs) { super(c, attrs); this.context = c; LayoutInflater.from(context).inflate(R.layout.custom_spinner, this, true); String[] strings = new String[] {}; List<String> items = new ArrayList<String>(Arrays.asList(strings)); emptyAdapter = new ArrayAdapter<String>(c, android.R.layout.simple_spinner_item, items); initViews(); } private void initViews() { spinner = (Spinner) findViewById(R.id.spinner); progress = (ProgressBar) findViewById(R.id.progress); } public void loading(boolean flag) { if (flag) spinner.setAdapter(emptyAdapter); progress.setVisibility(flag ? View.VISIBLE : View.GONE); } }
      
      







コントロールが読み込み中の場合、リスト内の可能なリスト値を非表示にする必要がありますspinner.setAdapter(emptyAdapter);



。 実際、プログレスバーを表示します。



AsyncTaskを使用する非同期読み込みで、コントロールの動作を制御できます。



  CustomSpinner spinner; ... @Override protected void onPreExecute() { spinner.loading(true); } ... @Override protected SpinnerAdapter doInBackground(Map<String, Object>... params) { // ,   -   SpinnerAdapter,     CustomSpinner return null; } ... @Override protected void onPostExecute(SpinnerAdapter result) { spinner.loading(false); if (result != null) spinner.setAdapter(result); }
      
      







松葉杖



まあ、もちろん、そしてそれらなしでどこに!



本質的に私たちはスピナーが欲しかったことを思い出してください。 したがって、制御動作は適切である必要があります。 選択した実装では、いくつかのギャグを実装する必要があります。



 public class CustomSpinner extends RelativeLayout { ... //      public void setOnItemSelectedListener(OnItemSelectedListener l) { spinner.setTag(getId()); spinner.setOnItemSelectedListener(l); } //    public void setAdapter(SpinnerAdapter adapter) { spinner.setAdapter(adapter); } //       public int getSelectedItemPosition() { return this.spinner.getSelectedItemPosition(); } //    public SpinnerAdapter getAdapter() { return this.spinner.getAdapter(); } }
      
      







メソッドgetAdapter(), setAdapter(), getSelectedItemPosition()



単純にアクションを内部スピナーに「転送」します。

setOnItemSelectedListener(OnItemSelectedListener l)



メソッドに注意する必要があります。 switch(*some_unique_value*)...case(R.id.model)



使用して次に何をするかを決定するすべてのコントロール(より正確だと思います)に1つのリスナーを使用します。 コントロール内のドロップダウンリストには一意のグローバル識別子がないため(すべてのR.id.spinner用)、ドロップダウンリストタグに親コントロールの識別子spinner.setTag(getId());



)を記述します。 これで、ドロップダウンリストの値を変更するハンドラーを呼び出すと、変更されたリストを特定できます。



ドロップダウンハンドラー:



 class SpinnerItemSelectedListener implements OnItemSelectedListener { @Override public void onItemSelected(AdapterView<?> paramAdapterView, View paramView, int paramInt, long paramLong) { int id = ((SimpleParameter) paramAdapterView.getAdapter().getItem( paramInt)).getId(); switch ((Integer) paramAdapterView.getTag()) { case R.id.city: initCityDependant(id); break; case ...: otherMethod(); break; default: break; } } @Override public void onNothingSelected(AdapterView<?> paramAdapterView) { } }
      
      







カスタムコントロールがSpinnerから直接継承された場合、これらの松葉杖は継承されなかった可能性があります。 しかし、悲しいかな。



型のCustomSpinner



新しい要素をアプリケーションインターフェイス(レイアウト)に挿入します。



 <org.solo12zw74.app.CustomSpinner android:id="@+id/model" android:layout_width="fill_parent" android:layout_height="wrap_content" />
      
      







私のフォームにはこのようなコントロールが25個あります。 レイアウトヘッダーでアプリケーションの名前空間を指定できることを読んだら、完全なクラス名org.solo12zw74.app.CustomSpinner



を記述する必要はないようorg.solo12zw74.app.CustomSpinner



。 しかし、今では何らかの理由でうまくいきませんでした。



あとがき



ご清聴ありがとうございました。 誰かがそのようなコントロールの実装に関する賢明な記事へのリンクを最初の方法で提供してくれたらとてもうれしいです(Spinnerから継承)。 または、onDraw()メソッドでプログレスバーを描画する方法を説明し、必要に応じて非表示にします。



All Articles