วิธีซ่อนรายการหนึ่งใน Android Spinner


101

ฉันกำลังหาวิธีซ่อนรายการหนึ่งในวิดเจ็ตสปินเนอร์ของ Android สิ่งนี้จะช่วยให้คุณสามารถจำลองสปินเนอร์โดยไม่ได้เลือกรายการใด ๆ และทำให้แน่ใจว่าการเรียกกลับ onItemSelected () จะถูกเรียกสำหรับทุกรายการที่เลือกเสมอ (หากรายการที่ซ่อนอยู่คือรายการ "ปัจจุบัน") โดยปกติจะมีรายการหนึ่งในสปินเนอร์ที่ไม่สร้างการเรียกกลับเสมอคือรายการปัจจุบัน

มีรหัสบางอย่างใน stackoverflow สำหรับวิธีปิดใช้งานรายการ (เป็นสีเทา) แต่ไม่ใช่วิธีการซ่อนรายการอย่างสมบูรณ์ราวกับว่าไม่มีอยู่จริง

หลังจากการทดลองหลายครั้งฉันได้พบกับโซลูชันที่ค่อนข้างแฮ็กซึ่งใช้ได้กับแพลตฟอร์ม Android ทั้งเก่าและใหม่ มีข้อบกพร่องเล็กน้อยเกี่ยวกับเครื่องสำอางซึ่งยากที่จะสังเกตเห็น ฉันยังอยากได้ยินวิธีแก้ปัญหาที่เป็นทางการมากกว่านี้นอกจาก "อย่าทำแบบนั้นด้วยสปินเนอร์"

สิ่งนี้จะซ่อนรายการแรกไว้ในตัวหมุนเสมอ แต่สามารถขยายได้อย่างง่ายดายเพื่อซ่อนรายการที่กำหนดเองหรือมากกว่าหนึ่งรายการ เพิ่มรายการจำลองที่มีสตริงว่างที่จุดเริ่มต้นของรายการสปินเนอร์ของคุณ คุณอาจต้องการตั้งค่าการเลือกสปินเนอร์ปัจจุบันเป็นรายการ 0 ก่อนที่กล่องโต้ตอบสปินเนอร์จะเปิดขึ้นซึ่งจะจำลองสปินเนอร์ที่ไม่ได้เลือก

ตัวอย่างการตั้งค่า Spinner ด้วยวิธี ArrayAdapter แทนที่:

List<String> list = new ArrayList<String>();
list.add("");   //  Initial dummy entry
list.add("string1");
list.add("string2");
list.add("string3");

// Populate the spinner using a customized ArrayAdapter that hides the first (dummy) entry
ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, list) {
    @Override
    public View getDropDownView(int position, View convertView, ViewGroup parent)
    {
        View v = null;

        // If this is the initial dummy entry, make it hidden
        if (position == 0) {
            TextView tv = new TextView(getContext());
            tv.setHeight(0);
            tv.setVisibility(View.GONE);
            v = tv;
        }
        else {
            // Pass convertView as null to prevent reuse of special case views
            v = super.getDropDownView(position, null, parent);
        }

        // Hide scroll bar because it appears sometimes unnecessarily, this does not prevent scrolling 
        parent.setVerticalScrollBarEnabled(false);
        return v;
    }
};

dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mySpinner.setAdapter(dataAdapter);

คุณพบอะไรใน interwebs อื่น ๆ ? คุณได้ลองทำอะไรไปบ้าง?
dldnh

ขอโทษนะฉันไม่รู้จะทำยังไง
Louisth

ทางออกที่ดี! แต่ผมคิดว่าtv.setVisibility(View.GONE);เส้นไม่จำเป็น การแสดงความคิดเห็นดูเหมือนจะไม่สร้างความแตกต่าง (ภาพ) อย่างน้อยใน Android 4.4.2 / KitKit (บน LG / Google Nexus 4)
Matthias

คำตอบในคำถามนี้ใช้ได้ดี ..
Rat-a-tat-a-tat Ratatouille

นี่อาจไม่ใช่การปรับปรุง แต่ฉันใช้setTag(1)บน textView ที่ตำแหน่ง 0 จากนั้นใช้convertView.getTag() != nullเพื่อพิจารณาว่ามุมมองที่ใช้ซ้ำเป็นมุมมองความสูง 0 ที่สร้างขึ้นสำหรับตำแหน่ง 0 หรือมุมมองปกติที่ใช้สำหรับรายการสปินเนอร์อื่น ๆ นี่คือสิ่งที่ฉันสามารถใช้super.getDropDownView(position, convertView, parent)บางครั้งแทนที่จะสร้างมุมมองใหม่เสมอ
Daniel Handojo

คำตอบ:


50

หากต้องการซ่อนรายการที่กำหนดเองหรือมากกว่าหนึ่งรายการฉันคิดว่าคุณสามารถใช้อะแดปเตอร์ของคุณเองและตั้งค่าดัชนี (หรือรายการดัชนีอาร์เรย์) ที่คุณต้องการซ่อน

public class CustomAdapter extends ArrayAdapter<String> {

     private int hidingItemIndex;

     public CustomAdapter(Context context, int textViewResourceId, String[] objects, int hidingItemIndex) {
         super(context, textViewResourceId, objects);
         this.hidingItemIndex = hidingItemIndex;
     }

     @Override
     public View getDropDownView(int position, View convertView, ViewGroup parent) {
         View v = null;
         if (position == hidingItemIndex) {
             TextView tv = new TextView(getContext());
             tv.setVisibility(View.GONE);
             v = tv;
         } else {
             v = super.getDropDownView(position, null, parent);
         }
         return v;
     }
 }

และใช้อะแดปเตอร์แบบกำหนดเองของคุณเมื่อคุณสร้างรายการ

List<String> list = new ArrayList<String>();
list.add("");   //  Initial dummy entry
list.add("string1");
list.add("string2");
list.add("string3");

int hidingItemIndex = 0;

CustomAdapter dataAdapter = new CustomAdapter(this, android.R.layout.simple_spinner_item, list, hidingItemIndex);

dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mySpinner.setAdapter(dataAdapter);

(ฉันยังไม่ได้ทดสอบโค้ด) หวังว่าจะช่วยได้


1
นี่ไม่ใช่วิธีแก้ปัญหา การอัปเดตคำถามให้รหัสที่ถูกต้อง
dldnh

13
หากไม่มี tv.setHeight (0) TextView จะยังคงมองเห็นได้
v4r

สวัสดีฉันใช้รหัสนี้เพื่อซ่อนรายการแรกในสปินเนอร์ของฉันมันใช้งานได้ดีสปินเนอร์ของฉันจะแสดงรายการที่สองให้ฉัน แต่เมื่อฉันคลิกที่รายการที่สองข้อความในรายการนั้นจะถูกตั้งค่าเป็นสปินเนอร์ของฉันฉัน ไม่ต้องการแสดงข้อความใด ๆ บนสปินเนอร์ของฉันเมื่อฉันคลิกไปที่รายการนั้นโปรดแนะนำฉันด้วย?
Achin

1
Awesome :) วิธีแก้ปัญหาง่ายๆ :)
Chaitanya

1
ใช้งานได้ดั่งใจ .. !
Krupa Kakkad

20

การซ่อนรายการที่ท้ายรายการทำได้ง่ายกว่าโดยการตัดทอนรายการ

แต่คุณต้องเลือกก่อนจึงจะปรากฏในสปินเนอร์จากนั้นตรวจสอบว่าการเลือกถูกเปลี่ยนเป็นรายการใดรายการหนึ่งที่แสดงหรือไม่

List<String> list = new ArrayList<String>();
list.add("string1");
list.add("string2");
list.add("string3");
list.add("[Select one]");
final int listsize = list.size() - 1;

ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this,android.R.layout.simple_spinner_item, list) {
    @Override
    public int getCount() {
        return(listsize); // Truncate the list
    }
};

dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mySpinner.setAdapter(dataAdapter);
mySpinner.setSelection(listsize); // Hidden item to appear in the spinner

3
ฉันใช้เวลาครึ่งชั่วโมงในการค้นหาวิธีการที่สะอาดและนี่เป็นแนวทางที่ดีที่สุด เพียงตัดรายการ แต่รายการนั้นมีอยู่จริง ยอดเยี่ยม.
KSdev

1
ดูเหมือนจะใช้ไม่ได้ใน Lollipop การทดสอบ [Select one] จะไม่ปรากฏใน Spinner ในตอนแรก รหัสเดียวกันใน Android เวอร์ชันเก่าดูเหมือนจะทำในสิ่งที่เราทุกคนต้องการ
Jonathan Caryl

1
ข้อความสปินเนอร์จะเปลี่ยนเป็น 'String3' ในการเปลี่ยนทิศทางแม้สปินเนอร์จะไม่ถูกแตะต้อง @Romich
Yksh

มีใครดูคำถามของฉันได้ไหม
Moeez

5

หากต้องการซ่อนรายการใด ๆ ในรายการแบบเลื่อนลงของสปินเนอร์คุณจะต้องส่งผ่านตำแหน่งของรายการที่ต้องซ่อนตามเกณฑ์ที่กำหนด ฉันประสบความสำเร็จในกรณีการใช้งานในการซ่อนรายการที่เลือกจากเมนูแบบเลื่อนลง

public class CustomAdapter extends ArrayAdapter<String> {

private List<String> dates;
private int hideItemPostion;

public CustomAdapter (Context context, int resource, List<String> dates) {
    super(context, resource,dates);
    this.dates=dates;
}
public void setItemToHide(int itemToHide)
{
    this.hideItemPostion =itemToHide;
}
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
    View v = null;
    if (position == hideItemPostion) {
        TextView tv = new TextView(getContext());
        tv.setVisibility(View.GONE);
        tv.setHeight(0);
        v = tv;
        v.setVisibility(View.GONE);
    }
    else
        v = super.getDropDownView(position, null, parent);
    return v;
}}

และการตั้งค่าอะแดปเตอร์ก็เป็นเช่นนี้

final CustomAdapter dataAdapter = new CustomAdapter(this,R.layout.spinner_item,dates);
    dataAdapter.setDropDownViewResource(R.layout.spinner_dropdown_item);
    spinner.setAdapter(dataAdapter);
    dataAdapter.setItemToHide(0);

ในการเลือกบางรายการจากเมนูแบบเลื่อนลงตำแหน่งต้องเปลี่ยนด้วย

 spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> adapterView, View view, final int i, long l) {
        dataAdapter.notifyDataSetChanged();
            mEPGDateSelector.setSelection(i);
            dataAdapter.setItemToHide(i);}

             @Override
        public void onNothingSelected(AdapterView<?> adapterView) {

        }
    });

1

เพื่อความสนใจฉันจึงหาวิธีแก้ปัญหาโดยใช้ "Prompt" เป็นคำใบ้ รหัสนี้สร้างขึ้นเพื่อXamarin.Androidแต่สามารถย้ายไปยัง Java ได้อย่างสมบูรณ์แบบภายใน 10 นาที ใช้มันแบบง่ายๆArrayAdapterโดยไม่ต้องเพิ่มรายการที่จัดทำดัชนีหรือนับดัชนีลงในอาร์เรย์ต้นทาง นอกจากนี้ยังตั้งค่าSpinnerGeolocation.SelectedItemIdเป็น -1 เมื่อไม่มีการเลือก ( hintคือรายการปัจจุบัน)

public class ArrayAdapterWithHint<T>: ArrayAdapter<T>
{
    protected bool HintIsSet = false;
    protected int HintResource = 0;

    public ArrayAdapterWithHint(Context context, int textViewResourceId,
                   T[] objects)
        : base(context, textViewResourceId, objects)
    {
    }
    public ArrayAdapterWithHint(Context context, int hintResource,
                   int textViewResourceId, T[] objects)
        : base(context, textViewResourceId, objects)
    {
        HintResource = hintResource;
    }
    public ArrayAdapterWithHint(Context context, int textViewResourceId,
             IList<T> objects)
        : base(context, textViewResourceId, objects)
    {
    }
    public ArrayAdapterWithHint(Context context, int hintResource,
                    int textViewResourceId, IList<T> objects)
        : base(context, textViewResourceId, objects)
    {
        HintResource = hintResource;
    }

    public override View GetDropDownView(int position, View convertView,
                ViewGroup parent)
    {
        if (HintIsSet)
            return base.GetDropDownView(position + 1,
                               convertView, parent);
        return base.GetDropDownView(position, convertView, parent);
    }

    public override View GetView(int position, View convertView,
                      ViewGroup parent)
    {
        if (!HintIsSet && parent is Spinner && 
                    !string.IsNullOrWhiteSpace((parent as Spinner).Prompt))
        {
            Insert((parent as Spinner).Prompt, 0);
            HintIsSet = true;
            (parent as Spinner).SetSelection(base.Count - 1);
        }
        if (HintIsSet && position >= base.Count - 1)
        {
            View hintView = base.GetView(0, convertView, parent);
            if (hintView is TextView)
                (hintView as TextView).SetTextAppearance(
                                                     Context, HintResource);
            return hintView;
        }
        if (HintIsSet && position < base.Count - 1)
            return base.GetView(position + 1, convertView, parent);
        return base.GetView(position, convertView, parent);
    }

    public override long GetItemId(int position)
    {
        if (HintIsSet)
        {
            if (position >= base.Count - 1)
                return -1;
            return position;
        }
        return base.GetItemId(position);
    }

    public override int Count
    {
        get
        {
            return base.Count > 0 && HintIsSet ? base.Count - 1 : base.Count;
        }
    }
}

มีใครดูคำถามของฉันได้ไหม
Moeez

1

ฉันพบวิธีนี้ซึ่งช่วยแก้ปัญหาของฉันได้

final Spinner mySpinner = (Spinner)findViewById(R.id.spinner_triptype);

   final ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,R.layout.spinner_item, R.id.weekofday, triptype_initial);

   final ArrayAdapter<String> adapter_temp = new ArrayAdapter<String>
(this,R.layout.spinner_item, R.id.weekofday, triptype_array);


   mySpinner.setAdapter(adapter);
    mySpinner.setOnTouchListener(new View.OnTouchListener() {
       @Override
       public boolean onTouch(View v, MotionEvent event) {
       // display your error popup here
        if(flag_spinner_isFirst){
           mySpinner.setAdapter(adapter_temp);
           flag_spinner_isFirst = false;
          }
           v.onTouchEvent(event);
           return true;

       }
    });

0

ฉันคิดว่าการตรวจสอบความถูกต้องใน Array List จะดีกว่าใน Spinner เพราะเมื่อรายการถูกกรองแล้วการเพิ่มใน Spinner จะปลอดภัย


0

อีกวิธีหนึ่งที่ได้ผลดีที่สุดสำหรับฉันคือการส่งคืนวัตถุมุมมองเปล่าใหม่ นี่เป็นแนวทางที่สะอาดมากเนื่องจากคุณไม่ได้เล่นกับองค์ประกอบอาร์เรย์

สร้างการขยายคลาสอะแดปเตอร์ของคุณ ArrayAdapter

ภายในวิธีการของคุณ

public View getView(int position, View convertView, ViewGroup parent) {
    View row = getCustomView();
    if(position==0) // put the desired check here.
         {
            row  = new View(context);
         }
    }
    return row;
}

0

นี่เป็นคำถามเก่ามาก แต่ฉันได้พบวิธีที่ดี (และอาจ) ที่ดีในการไม่แสดงรายการแรกเช่นกัน แรงบันดาลใจจากคำตอบของ @ Romich ฉันได้เพิ่มตรรกะที่คล้ายกันเพื่อข้ามรายการแรก

สิ่งนี้ซ่อนจำนวนรายการโดยพลการได้อย่างมีประสิทธิภาพ (1 โดยค่าเริ่มต้น) โค้ดจะรายงานเฉพาะขนาดของวัตถุที่จะแสดงผลให้สั้นกว่าที่เป็นจริงและยังเปลี่ยนดัชนีของรายการที่จะแสดงผลดังนั้นเราจึงข้ามจำนวนรายการโดยพลการ

เพื่อให้สิ่งต่างๆง่ายขึ้นฉันได้ยกเว้นวิธีแก้ปัญหาที่ฉันกำลังใช้อยู่ซึ่งรองรับการซ่อนรายการแบบสุ่ม แต่สามารถจัดการได้อย่างง่ายดายด้วยการปรับแต่งโค้ดเพียงเล็กน้อย

class ArrayAdapterCustom(context: Context, textViewResourceId: Int, vararg objects: String)
    : ArrayAdapter<String>(context, textViewResourceId, objects) {

    //Can skip first n items (skip 1 as default)
    var hideFirstItemsCount = 1

    override fun getCount(): Int {
        return super.getCount() - hideFirstItemsCount
    }

    override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View {
        return super.getDropDownView(position + hideFirstItemsCount, convertView, parent)
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.