2014年8月15日 星期五

[Android]spinner +BaseAdapter listview

最近在研究如何自訂listView,在網路上看了相關的文件
所以就來玩看看



一般來說一個最簡單的ListView是長這樣
listView.jpg
如果利用內建SampleAdapter就大概會是這樣
listView2.jpg
那如果要放圖或者checkbox、Button等呢
那麼就利用BaseAdapter來就可以辦到了
步驟:
我的例子是利用spinner來選取listview,並用BaseAdapter來建立自己的listview
create spinner就不說了


List.java
public class HelloList extends Activity{
    private Spinner sp1;
    private ArrayAdapter<String> adapter1;
    private ArrayList<String> lstSpinner = new ArrayList<String>();
    
    private MyListViewAdapter base;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub

        super.onCreate(savedInstanceState);
        setContentView(R.layout.list);
        init();
    }
    
    private void init()
    {
      lv = (ListView)findViewById(R.id.activity_list_listView1);
      sp1 = (Spinner) findViewById(R.id.login_spinner1);
     
      
      lst1= new ArrayList<String>();
      lst1.add("Hank");
      lst1.add("Lin");
      lst1.add("Paul");
      
      
      
      lstSpinner.add("ListView Type 1");
      lstSpinner.add("ListView Type 2");
      lstSpinner.add("ListView Type 3");
      lstSpinner.add("ListView Type 4");
      
      adapter1 = new ArrayAdapter<String>(HelloList.this, android.R.layout.simple_spinner_item, lstSpinner);
      sp1.setAdapter(adapter1);
      
      sp1.setOnItemSelectedListener(new Spinner.OnItemSelectedListener(){

        @Override
        public void onItemSelected(AdapterView<?> aparent, View view, int position, long id) {
            // TODO Auto-generated method stub

            switch(position){
            case 0:
                  base =new MyListViewAdapter(HelloList.this, lst3) ;
                 lv.setAdapter(base);
                break;
            }
        }
      });
}
}


再來看看自訂的baseAdapter
  • 首先create 你的Adapater然後extands BaseAdapter 你會需要Override 4個methods
    • View getView(int position, View convertView, ViewGroup parent):修改View的內容
    • int getCount() : 取得listview有多少列
    • Object getItem(int position):取得某一列的內容
    • long getItemId(int position):取得某一列的ID
  • 建立一個class ViewTag去存取它的屬性
  • 在getView裡面去讀取ViewTag和設定對應元件


MyListViewAdapter.java
public class MyListViewAdapter extends BaseAdapter
      {
         Context context;
         ArrayList<HashMap<String, Object>> lst;
         LayoutInflater inflater;
         private Handler viewtaganimation= new Handler();//icon動畫

         
        public MyListViewAdapter(Context ctx, ArrayList<HashMap<String, Object>> l)
        {
          super();
          // TODO Auto-generated constructor stub

          this.context = ctx;
          this.lst = l;
          inflater = LayoutInflater.from(ctx);
        }
        
       
        @Override
        public View getView(int position, View convertView, ViewGroup parent)
        {
            ViewTag viewTag;
            viewtaganimation= new Handler();
            
            if(convertView == null){
            convertView = inflater.inflate(R.layout.simple_list_item_3,null);//實體化view

            viewTag = new ViewTag(
                    (ImageView)convertView.findViewById(R.id.simple_list_item_3_imageView1), 
                    (TextView)convertView.findViewById(R.id.simple_list_item_3_textView1),
                    (TextView)convertView.findViewById(R.id.simple_list_item_3_textView2),
                    (AnimationDrawable) context.getResources().getDrawable(R.anim.animation2));

             convertView.setTag(viewTag); //绑定ViewTag對象

            
            }
            else{
                 viewTag = (ViewTag) convertView.getTag();
            }
            //設定元件

            viewTag.tv1.setText(lst.get(position).get("item1").toString());
            viewTag.tv2.setText(lst.get(position).get("item2").toString());
            viewTag.icon.setImageDrawable(viewTag.ad);
            
            //animation

            viewtaganimation.postDelayed(new MyRunnable(viewTag.ad,viewTag.icon),200);
            return convertView;

        }
        @Override
        public int getCount() {
            // TODO Auto-generated method stub

            return lst.size(); //共有幾列

        }
            
        @Override
        public Object getItem(int position) {
            // TODO Auto-generated method stub

            return null;
        }

        @Override
        public long getItemId(int position) {
            // TODO Auto-generated method stub

            return 0;
        }
        //宣告成一個類別讓該列屬性去讀取

        class ViewTag{
              ImageView icon;
              TextView tv1,tv2;
              AnimationDrawable ad;
               
        public ViewTag(ImageView icon, TextView tv1, TextView tv2, AnimationDrawable ad){
            this.icon = icon;
            this.tv1 = tv1;
            this.tv2 = tv2;
            this.ad=ad;
             }
    }
        private class MyRunnable implements Runnable
          {
            private AnimationDrawable a;
            private ImageView k;
            
            public MyRunnable(AnimationDrawable a, ImageView k)
            {
                
              this.a = a;
              this.k=k;
           
            }
            @Override
            public void run()
            {
                this.a.start();
                this.k.invalidate();
                
            }
          }
}

執行結果:
picasion.com_cedf58c6f5f7b96392883240128bc68b.gif

在這裡我做了一個icon動畫,只要程式進去自動會跑annimation icon
步驟如下:
  • 在BaseAdapter中宣告一個私有類別成員 private Handler viewtaganimation= new Handler();
  • 在GetView裡面new一個Handler
  • 宣告要一個class MyRunnable去實作Runnable
  • 最後viewtaganimation.postDelayed(new MyRunnable(viewTag.ad, viewTag.icon), 200);

issue

這邊遇到問題是:在模擬器上面執行動畫沒問題,但是跑在手機上面卻不會執行
所以就在Run裡加了這行
this.k.invalidate();
invalidate
invalidate()是用来刷新View的,必须是在UI线程中进行工作。比如在修改某个view的显示时,调用invalidate()才能看到重新绘制的界面。Here
詢問過老師後他給我的解答是:
手機大都有客製的Launcher, 當View改變要自己通知自己invalidate,否則會focus在各家客製手機的Launcher上
摁,還是有點不太懂

沒有留言:

張貼留言