web-dev-qa-db-ja.com

Spinnerはテキストをラップしません-これはAndroidバグですか?

Spinnerアイテムのテキストが長すぎて1行に収まらない場合、テキストは折り返されずに切り取られます。これはonlyAPIレベル> = 11の場合のみです。以下にスクリーンショットを示しますAndroid4.2.2(左)間違った動作とAndroid2.3.3(右)期待どおりに見える場所。

_Android:singleLine="false"_は、ここでは単に無視されます。したがって、_Android:lines_、_Android:minLines_などのような他のすべての試みと同様に、TextViewはウィンドウ幅よりもはるかに広いようです。

他の人が同じ問題を抱えているのを見ましたが、誰も解決策を見つけることができませんでした。だから、これはシステムのバグですか? OSのバージョン間のこの矛盾は意図したものではないと思います。


ご注意ください:

比較的単純な解決策を示唆する回答がいくつかありました。

  • カスタムAdapterを作成し、getView()およびgetDropDownView()をオーバーライドします。この時点ではまだ元の問題が残っているため、これは解決策ではありません。適切な行の折り返しを処理するためにレイアウトはどのように見える必要があるのでしょうか?

  • ドロップダウンビューのTextViewを親ViewGroupにラップします。 _Android:layout_width="match_parent"_では機能しません。親の幅が奇妙なことに無制限に見えるためです。

  • ドロップダウンビューに固定幅を与えます。これは、Spinnerが持つことができるさまざまな幅には適していません。

  • そしてもちろん、テキストのどこかに_\n_ sを手動で挿入することは解決策ではありません。


次のコードで再現します。

UPDATE:また、これをサンプルプロジェクトとして GitHubダウンロード にアップロードしました

/res/values/arrays.xml:

_<string-array name="items">
    <item>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.</item>
    <item>At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est.</item>
</string-array>
_

/res/layout/spinner_item.xml:

_<TextView xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:id="@Android:id/text1"
    style="?android:attr/spinnerDropDownItemStyle"
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content"
    Android:ellipsize="none"
    Android:minHeight="?android:attr/listPreferredItemHeight"
    Android:singleLine="false" />
_

Adapterを設定:

_spinner.setAdapter(ArrayAdapter.createFromResource(this,
            R.array.items,
            R.layout.spinner_item));
_
63

ホロテーマスピナーでは、デフォルトでドロップダウンモードが使用されます。そして、デフォルトスタイルをオーバーライドするすべての動きは、スピナーモードをダイアログモードに切り替えるだけで、API 11のように複数行テキストを正常にラップします。代わりに、new Spinner(context, Spinner.MODE_DIALOG)またはxml:_Android:spinnerMode="dialog"_でスピナーを作成できます。ただし、ドロップダウンではなくダイアログであるため、問題は解決しません。

この問題の別の解決策を見つけました。getDropDownViewArrayAdapterメソッドをオーバーライドし、setSingleLine(false)をpostメソッドのビューに配置します。したがって、ビューが完全に作成されると、テキストが適切な行にラップされます。

_@Override
public View getDropDownView(final int position, View convertView, ViewGroup parent) {
    if (convertView == null) {
        convertView = new TextView(_context);
    }

    TextView item = (TextView) convertView;
    item.setText("asddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd");
    final TextView finalItem = item;
    item.post(new Runnable() {
        @Override
        public void run() {
            finalItem.setSingleLine(false);
        }
    });
    return item;
}
_

更新:

そして、ここに別の答えがあります。

PopupWindowでリストビューを手動でラップし、クリックするとTextViewの下に表示され、listItemをクリックすると非表示になります。

アイデアを示すための単純な実装:

_public class MySpinner extends TextView {
    private PopupWindow _p;
    private ListView _lv;
    public MySpinner(Context context) {
        super(context);
        init();
    }
    public MySpinner(Context context, AttributeSet attributeSet){
        super(context, attributeSet);
        init();
    }

    private void init(){
        setBackgroundResource(R.drawable.spinner_background);
        final List<String> list = new ArrayList<String>();
        list.add("Very long text AAAAAAAAAAAAAAAA");
        list.add("1 Very long text AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
        list.add("2 Very long text A");
        list.add("3 Very long text AAAAAAAAA");

        setMinimumWidth(100);
        setMaxWidth(200);

        _lv = new ListView(getContext());
        _lv.setAdapter(new ArrayAdapter<String>(getContext(), R.layout.simple_list_item_1, list));
        _lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                _p.dismiss();
                setText(list.get(i));
            }
        });

        setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {

                _p = new PopupWindow(getContext());
                _p.setContentView(_lv);
                _p.setWidth(getWidth());
                _p.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
                _p.setTouchable(true);
                _p.setFocusable(true);
                _p.setOutsideTouchable(true);
                _p.showAsDropDown(view);
            }
        });
    }
}
_
32
Kolchuga

ここでのソリューションの組み合わせのみが私のために働いた(Android 5.1でもテストされた):

spinner_item.xml

<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
             Android:layout_width="match_parent"
             Android:layout_height="wrap_content">

  <TextView
    Android:id="@Android:id/text1"
    style="?android:attr/spinnerItemStyle"
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content"
    Android:singleLine="false"
    Android:textAlignment="inherit"/>
</LinearLayout>

コード

  final ArrayAdapter<String> spinnerArrayAdapter=new ArrayAdapter<String>(activity,R.layout.spinner_item,Android.R.id.text1,spinnerItemsList)
  {
  @Override
  public View getDropDownView(final int position,final View convertView,final ViewGroup parent)
    {
    final View v=super.getDropDownView(position,convertView,parent);
    v.post(new Runnable()
    {
    @Override
    public void run()
      {
      ((TextView)v.findViewById(Android.R.id.text1)).setSingleLine(false);
      }
    });
    return v;
    }
  };
  spinnerArrayAdapter.setDropDownViewResource(Android.R.layout.simple_spinner_dropdown_item);
13

ダイアログスタイルのスピナーに切り替えることで、この問題を解決しました。

<Spinner
  ...
Android:spinnerMode="dialog" />
13
cVoronin

TextViewの周りにLinearLayoutを追加すると、テキストを正しく折り返すことができます。

レイアウト(common_domainreferencemodel_spinner_item.xml):

<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_height="wrap_content"
    Android:layout_width="match_parent"
    Android:padding="4dp">

       <TextView
            Android:id="@+id/nameTextView"
            Android:singleLine="false"
            Android:layout_width="match_parent"
            Android:layout_height="wrap_content" />

</LinearLayout>

アダプタ:

public class DomainReferenceModelAdapter extends ArrayAdapter<DomainReferenceModel> {

    private List<DomainReferenceModel> objects;
    private LayoutInflater inflater;
    private int oddRowColor = Color.parseColor("#E7E3D1");
    private int evenRowColor = Color.parseColor("#F8F6E9");

    public DomainReferenceModelAdapter(Context context, int resource, List<DomainReferenceModel> objects) {
        super(context, resource, objects);
        this.objects = objects;
        this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    static class ViewHolder {
        public TextView nameTextView;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        return getViewInternal(position, convertView, parent, false);
    }

    @Override
    public View getDropDownView(int position, View convertView, ViewGroup parent) {
        return getViewInternal(position, convertView, parent, true);
    }

    private View getViewInternal(int position, View convertView, ViewGroup parent, boolean isDropdownView) {
        View view = convertView;
        if (view == null) {
            view = inflater.inflate(R.layout.common_domainreferencemodel_spinner_item, null);
            ViewHolder viewHolder = new ViewHolder();
            viewHolder.nameTextView = (TextView) view.findViewById(R.id.nameTextView);
            view.setTag(viewHolder);
        }
        if (isDropdownView) {
            view.setBackgroundColor(position % 2 == 0 ? evenRowColor : oddRowColor);
        }
        ViewHolder holder = (ViewHolder) view.getTag();
        DomainReferenceModel model = objects.get(position);
        holder.nameTextView.setText(model.getName());
        return view;
    }

}
7
Mike Schall

私が試したことから、Spinnerテーマを使用中にHoloで複数行のドロップダウンアイテムを実現することはできません。

回避策は次のとおりです。

  • Spinnerを継承しないHoloのスタイルを作成します。これにより、複数行のドロップダウンアイテムが有効になります。
  • スピナーのスタイルを「手動」にして、Holo- themedのようにします。

これにより、(閉じた状態と開いた状態が表示されます):

enter image description here

実装の詳細:

HoloSpinnerテーマから継承し、Spinnerドロップダウン項目に複数の行を表示する方法は、設定してもドロップダウンアイテムのTextViewsingleLine属性をfalseに追加し、カスタムレイアウトを提供します。私はHoloスタイルを維持しようとしましたが、

Android:spinnerStyle
Android:spinnerItemStyle 
Android:spinnerDropDownItemStyle 

スタイル属性(これらの属性の使用例 here )が、複数行の結果を生成することができませんでした。

ただし、Spinnerのスタイルをオーバーライドし、spinnerStyleからHoloを継承しない場合:

 <style name="AppTheme" parent="Android:Theme.Holo.Light">
    <item name="Android:spinnerStyle">@style/spinnerStyle</item>
</style>

<--no parent attribute-->
 <style name="spinnerStyle">
    <item name="Android:clickable">true</item>
</style>

ドロップダウンアイテムは複数行の表示をサポートします。しかし、今ではHoloSpinnerテーマを失い、閉じた状態はTextViewではなくSpinnerのように見え、矢印も視覚的な手がかりもないSpinner。代わりにspinnerStyle parentをparent="Android:style/Widget.Spinnerに設定した場合:

<style name="spinnerStyle" parent="Android:style/Widget.Spinner">
    <item name="Android:clickable">true</item>
</style>

Spinnerの閉じた状態には矢印が表示されますが、Spinnerアプリの外に見える灰色のホロHoloのようなスタイルになります。

したがって、可能な解決策は次のとおりです。

  • spinnerStyleのテーマをオーバーライドし、Holoを親に使用しないでください。 これにより、DropDownアイテムの複数行テキストが有効になります。
  • Spinner背景を変更して、Holoテーマを継承するようにします。

以下に例を示します。

基本的なアクティビティを作成します。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Spinner spinner = (Spinner)findViewById(R.id.styled_spinner);

    spinner.setAdapter(ArrayAdapter.createFromResource(this,
            R.array.items,
            R.layout.spinner_item));        
}

アクティビティレイアウト:

<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:tools="http://schemas.Android.com/tools"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:padding="50dip"
    tools:context=".MainActivity" >

    <Spinner
        Android:id="@+id/styled_spinner"
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"/>

</LinearLayout>

スタイル:

<resources xmlns:Android="http://schemas.Android.com/apk/res/Android">
    <style name="AppTheme" parent="Android:Theme.Holo.Light">
        <item name="Android:spinnerStyle">@style/spinnerStyle</item>
    </style>
    <style name="spinnerStyle">
        <item name="Android:clickable">true</item>
        <item name="Android:background">@drawable/spinner_background_holo_light</item>
    </style>
</resources>

描画可能なフォルダーに、spinner_background_holo_lightを配置します。

<selector xmlns:Android="http://schemas.Android.com/apk/res/Android">
    <item Android:state_enabled="false"
        Android:drawable="@drawable/spinner_disabled_holo_light" />
    <item Android:state_pressed="true"
        Android:drawable="@drawable/spinner_pressed_holo_light" />
    <item Android:state_pressed="false" Android:state_focused="true"
        Android:drawable="@drawable/spinner_focused_holo_light" />
    <item Android:drawable="@drawable/spinner_default_holo_light" />
</selector>

drawables-hdpiフォルダーにこれらのドロアブルを含めます:

enter image description here spinner_default_holo_light.9.png

enter image description here spinner_disabled_holo_light.9.png

enter image description here spinner_focused_holo_light.9.png

enter image description here spinner_pressed_holo_light.9.png

これにより、上記のスクリーンショットに示すように、Holoをテーマにした閉じた状態と複数行のアイテムを持つスピナーが生成されます。

この例のドロップダウン項目はHolo- themedではありませんが、ドロップダウン項目の複数行表示が本当に重要な場合、おそらく許容可能なトレードオフです。

この例では、マニフェストでAndroid:minSdkVersion14に設定され、Android:targetSdkVersion17に設定されました。

Holoグラフィックとspinner_background_holo_light.xmlコードは、 HoloEverywhere Copyright(c)2012 Christophe Versieux、Sergey Shatunovからのものです。ライセンスの詳細については、リンク先のgithubプロジェクトを参照してください。

6
Gunnar Karlsson

Androidにはバグがあると思います。これを試すことができます。テキストからスペースを削除して表示すると、正常に機能します。 textviewの長さが文字列の長さより小さい場合、スペースの後のすべての文字を無視します。回避策として、これを試すことができます:

サンプルコードを使用して、multiline_spinner_dropdown_item.xmlという名前のres/layoutフォルダーにファイルを追加します。

<CheckedTextView xmlns:Android="http://schemas.Android.com/apk/res/Android"
style="?android:attr/spinnerDropDownItemStyle"
Android:singleLine="false"
Android:layout_width="match_parent"
Android:layout_height="?android:attr/listPreferredItemHeight"
Android:ellipsize="Marquee" />

スピナーを作成するときに、このレイアウトからスピナーを作成します。

何かのようなもの :

ArrayAdapter.createFromResource(this, items, R.layout.multiline_spinner_dropdown_item);

基本的に、Android.R.layout.simple_spinner_dropdown_itemレイアウトをプロジェクトにコピーし、CheckedTextViewでsingleLine属性をfalseに設定してレイアウトを変更します。

3
lokoko

私は同じ問題に直面しました。スピナーのドロップダウンリストに2行表示したいのですが、見つけたすべての解決策は、このような単純な問題を解決するのに不合理に思えます。 Spinnerソースコード を調査し、属性Android:singleLine = "false"でcustom .xmlを使用すると、

<CheckedTextView xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:id="@+id/multiline_spinner_text_view"
    Android:layout_width="fill_parent"
    Android:layout_height="?android:attr/listPreferredItemHeight"
    Android:singleLine="false" />

デフォルト ArrayAdapter、次のコードは ListPopupWindow で実行される

    @Override
       View More obtainView(int position, boolean[] isScrap) {
            View view = super.obtainView(position, isScrap);

           if (view instanceof TextView) {
                ((TextView) view).setHorizontallyScrolling(true);
            }

            return view;        
}

それが、リストの行ごとに1行の文字列のみが表示される理由です。実際にはスクロールしています。

このような問題を解決するには、ViewをTextViewのnot instanceにして、TextViewをFrameLayoutまたはLinearLayout内に配置するだけです。

   <LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content" >

        <CheckedTextView
            Android:id="@+id/multiline_spinner_text_view"
            Android:layout_width="fill_parent"
            Android:layout_height="?android:attr/listPreferredItemHeight"
            Android:singleLine="false" />

    </LinearLayout>

そして

ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, 
               R.layout.multiline_spinner_dropdown_item,R.id.multiline_spinner_text_view,
                awasomeListValues);

このソリューションは、スピナーモード(MODE_DROPDOWNとMODE_DROPDOWN)の両方で機能します。

3
girlOnSledge

この答えを読んで: textviewキャストエラー:-Android.widget.LinearLayoutをAndroid.widget.TextViewにキャストできません そしてこのトピック、私はこの問題を解決できます:TextViewをラップするLinearLayoutが必要です(スピナーテキスト)テキストが画面から出ないようにするために、解決すべき問題がいくつかあります。最初に、レイアウトを作成します(私はそれをspinner_dd_item.xmlと呼びました):

    <LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
        xmlns:tools="http://schemas.Android.com/tools"
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:orientation="vertical">

        <TextView
            Android:id="@+id/simple_spinner_dropdown"
            Android:layout_width="match_parent"
            Android:layout_height="match_parent"
            Android:paddingBottom="5dp"
            Android:paddingLeft="10dp"
            Android:paddingRight="10dp"
            Android:paddingTop="5dp"
            Android:textColor="@color/colorAccent"
            tools:text="Hello" />
    </LinearLayout>

次のステップでは、ArrayAdapterインスタンスを作成してスピナーに設定します。

    ArrayAdapter<CharSequence> arrayAdapter = new ArrayAdapter<CharSequence>(getActivity(), R.layout.spinner_dd_item,
            R.id.simple_spinner_dropdown, hashmapToString(hashMap, keys)) {
        @Override
        public View getDropDownView(int position, View convertView, ViewGroup parent) {
            return getView(position, convertView, parent);
        }
    };
    spinner.setAdapter(arrayAdapter);

LinearLayoutを追加し、TextViewを指定し、getDropDownViewをオーバーライドして、データセット内の指定した位置にデータを表示するビューを取得する必要があるため、ArrayAdapterにレイアウト名とTextView idを追加することを忘れないでください。これで、スピナーが新しいバージョンと古いバージョンでうまく動作していることがわかりますAndroidバージョン

1
Jaco

Androidはこの場合に既存のスタイルを持っていることがわかりました

final Spinner pelanggaran = (Spinner) findViewById(R.id.pelanggaran);
ArrayAdapter<CharSequence> pelanggaran_adapter = ArrayAdapter.createFromResource(this,R.array.pelanggaran_array, Android.R.layout.simple_expandable_list_item_1);
pelanggaran_adapter.setDropDownViewResource(Android.R.layout.simple_expandable_list_item_1);
pelanggaran.setAdapter(pelanggaran_adapter);

問題が解決したことを願っています。

1
Fajar Rukmo

TextViewLinearLayoutで囲むだけです:

<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
              Android:layout_width="match_parent"
              Android:layout_height="wrap_content">
    <TextView
            Android:id="@Android:id/text1"
            Android:layout_width="match_parent"
            Android:layout_height="wrap_content"/>
</LinearLayout>
0
mixel
ArrayAdapter<?> specAdapter =
   ArrayAdapter.createFromResource(
       getActivity().getBaseContext(),
       aa[position],
       Android.R.layout.select_dialog_item);
specAdapter.setDropDownViewResource(Android.R.layout.select_dialog_item);
0
user5723352

これと同じ問題があり、解決策を見つけました。

テキストを初期表示とドロップダウンビューでも折り返したいと思いました。

テキストは最初の表示で折り返されていたので、ドロップダウンの場合、textviewを囲む固定幅の線形レイアウトのカスタムビューの使用を推奨する別のソリューションが見つかりました。これにより、スピナーのドロップダウンと最初の選択のドロップダウンが正しく表示されました。ただし、これは古いデバイスで大きな問題を引き起こしました。

他の何かを選択しようとすると、最初の表示は更新されず、テキストは積み重ねられたように見えました。そして、下に積み上げられたため、背景を追加しても役に立ちませんでした。 enter image description here

アダプターには、スピナーの最初の選択で表示されるものとは異なるビューをドロップダウンに設定できるsetDropDownViewResource()というメソッドがあります。

 import org.holoeverywhere.widget.Spinner;

 ArrayAdapter adapter1 = ArrayAdapter.createFromResource(this,R.array.array_of_strings,R.layout.simple_list_item_1);
 adapter1.setDropDownViewResource(R.layout.my_simple_list_item_1);
 spQ1.setAdapter(adapter1);

この例では、simple_list_itemはAndroidおよびmy_simple_list_itemによって提供されるデフォルトのビューです

<LinearLayout
xmlns:Android="http://schemas.Android.com/apk/res/Android" 
Android:layout_width="300dp"
Android:layout_height="wrap_content" >   

<TextView
  Android:id="@+id/Android:text1"
  Android:layout_width="wrap_content"
  Android:layout_height="50dp"
  Android:ellipsize="Marquee"
  Android:layout_gravity="center_vertical"
  Android:singleLine="false"/>

</LinearLayout> 

これで、テキストはスピナーのドロップダウンビュー内と、表示されているスピナー内にラップされます。

0

これを機能させるために私がやったことは次のとおりです。

ArrayAdapter<KeyValue> adapter = new ArrayAdapter<>(getContext(), R.layout.simple_dropdown_item_multiline, R.id.nameTextView, choices);

そして、これは「simple_dropdown_item_multiline」の内容です:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
          Android:layout_width="match_parent"
          Android:layout_height="wrap_content">

<TextView Android:id="@+id/nameTextView"
          style="?android:attr/dropDownItemStyle"
          xmlns:Android="http://schemas.Android.com/apk/res/Android"
          Android:layout_width="match_parent"
          Android:layout_height="wrap_content"
          Android:ellipsize="Marquee"
          Android:paddingBottom="@dimen/large"
          Android:paddingTop="@dimen/large"
          Android:singleLine="false"
          Android:textAppearance="?android:attr/textAppearanceLargePopupMenu"/>
0
Marco C.