国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android使用ListView實現滾輪的動畫效果實例

2019-10-22 18:33:20
字體:
來源:轉載
供稿:網友

之前收到一個需求,需要把一個數據展示列表頁面做成像滾輪那樣的動畫效果:中間最大然后向上下兩端逐漸縮小。我想了想iOS那邊自帶滾輪組件,安卓得自己去實現,目前網上仿ios的滾輪組件的也有一些,但是感覺不適合我,我的要求沒那么復雜,于是決定自己動手去實現一下。

動手前先分析一下應該怎么做,歸根到底只是要實現縮放效果,由中間向兩邊變小,當一個item越接近中間就放大,越遠離中間就縮小。那么可以通過先獲取ListView的中點,然后獲取當前可視的所有item跟ListView的中點的垂直距離計算出一個比例,然后將item的大小根據這個比例進行縮放,各個item跟ListView的中點的垂直距離不同,計算出來的比例也就不同,然后每次滾動的時候都計算比例然后進行縮放,這樣應該就能實現我們想要的效果了。

因為一開始我的列表展示就是用ListView做的,有其他效果在里面,也不方便換其他組件,所以依然還是用ListView實現就好了。由于我們是每次一滾動都要進行縮放,ListView有提供一個OnScrollListener,它的onScroll方法每次一開始滾動就會調用,所以我們選擇重寫它。當它被調用的時候,我們就開始獲取ListView中點,然后開始計算每個item的距離進行縮放.

/**   * 中點的Y坐標   */   private float centerY = 0f;   @Override   public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {     //計算中點     centerY = getHeight()/2;     //判斷中點的有效性     if(centerY <= 0){       return;     }     //開始對當前顯示的View進行縮放     for(int i = 0; i < visibleItemCount; i++){       //獲取item       View temp_view = getChildAt(i);       //計算item的中點Y坐標       float itemY = temp_view.getBottom()-(temp_view.getHeight()/2);       //計算離中點的距離       float distance = centerY;       if(itemY > centerY){         distance = itemY - centerY;       }else{         distance = centerY - itemY;       }       //根據距離進行縮放       temp_view.setScaleY(1.1f - (distance / centerY) < 0 ? 0 : 1.1f - (distance / centerY));       temp_view.setScaleX(1.1f - (distance / centerY) < 0 ? 0 : 1.1f - (distance / centerY));       //根據距離改變透明度       temp_view.setAlpha(1.1f - (distance / centerY) < 0 ? 0 : 1.1f - (distance / centerY));     }   } 

后面不想加demo了,所以直接上整個ListView的代碼吧

/**  * 模仿滾輪動畫縮放的ListView  * Created by xu on 2017/3/3.  */ public class XuListView extends ListView implements AbsListView.OnScrollListener {   private static final String TAG = "XuListView";    /**    * 中點的Y坐標    */   private float centerY = 0f;    public XuListView(Context context, AttributeSet attrs) {     super(context, attrs);     //設置一個滾動監聽     setOnScrollListener(this);   }    @Override   public void onScrollStateChanged(AbsListView view, int scrollState) {    }    @Override   public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {     //計算中點     centerY = getHeight()/2;     //判斷中點的有效性     if(centerY <= 0){       return;     }     //開始對當前顯示的View進行縮放     for(int i = 0; i < visibleItemCount; i++){       //獲取item       View temp_view = getChildAt(i);       //計算item的中點Y坐標       float itemY = temp_view.getBottom()-(temp_view.getHeight()/2);       //計算離中點的距離       float distance = centerY;       if(itemY > centerY){         distance = itemY - centerY;       }else{         distance = centerY - itemY;       }       //根據距離進行縮放       temp_view.setScaleY(1.1f - (distance / centerY) < 0 ? 0 : 1.1f - (distance / centerY));       temp_view.setScaleX(1.1f - (distance / centerY) < 0 ? 0 : 1.1f - (distance / centerY));       //根據距離改變透明度       temp_view.setAlpha(1.1f - (distance / centerY) < 0 ? 0 : 1.1f - (distance / centerY));     }   } } 

這樣基本就實現了我們想要的效果了

android,滾輪動畫,ListView實現滾輪

但是現在有一個問題,就是第一個item和最后一個item無法滾動到中間從而放大突出顯示。對此我暫時想了兩個方法去解決:1、在頭尾各種添加一些空白的item,使我們需要顯示的數據都可以滾動到最中間。(我現在就是這么做的);2、使整個列表實現循環滾動。

添加空白的item的話,我是通過修改adapter去實現的。數據源是一個數組,我在數組前面和后面各加一些特殊的數據,adapter實現getview的時候,如果發現當前item的數據是特殊數據,那么item就變透明,從而實現了我們原本要顯示的數據都可以被滾動最中間;

先從數據源下手,從頭尾填充特殊的數據

public class MainActivity extends AppCompatActivity {   XuListView mLisetview;   MyAdapter adapter;   ArrayList<String> nos = new ArrayList<String>();   @Override   protected void onCreate(Bundle savedInstanceState) {     super.onCreate(savedInstanceState);     setContentView(R.layout.activity_main);          mLisetview = (XuListView) findViewById(R.id.list_test);      ArrayList<String> temp = new ArrayList<String>();     for(int i = 0;i<10;i++){       temp.add(i+"");     }     adapter = new MyAdapter(this,temp);     mLisetview.setAdapter(adapter);     resetitem(mLisetview);   }    /**    * 在頭尾填充透明的item數據    */   private void resetitem(ListView listview) {      if(listview == null){       return;     }     //獲取屏幕高度     WindowManager wm =getWindowManager();     int displayheight = wm.getDefaultDisplay().getHeight();     //計算一個item的高度     int itemhight = 0;     if(adapter!=null){       View v=(View)adapter.getView(0, null, listview);       v.measure(           View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),           View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));       itemhight=v.getMeasuredHeight();     }     //根據Item的高度和屏幕的高度計算需要多少個item可以填滿一半的屏幕     int newcount = ((displayheight/2)/itemhight);     //填充前面的空白item     for (int i = 1; i <= newcount; i++) {       nos.add("full");     }     //添加我們需要顯示的數據     for(int i = 0;i<10;i++){       nos.add(i+"");     }     //填充后面的空白item     for (int i = 1; i <= newcount; i++) {       nos.add("full");     }     //刷新數據     adapter.refreshData(nos);   } } 

然后adapter里面對頭尾的特殊數據進行識別,將item變為透明的。

public class MyAdapter extends BaseAdapter {    ArrayList<String> nos = new ArrayList<String>();   private Context context;    public MyAdapter(Context context, ArrayList<String> nos){     this.context = context;     this.nos = nos;   }   public void refreshData(ArrayList<String> nos) {     this.nos = nos;     notifyDataSetChanged();   }   @Override   public int getCount() {     return nos.size();   }    @Override   public Object getItem(int position) {     return nos.get(position);   }    @Override   public long getItemId(int position) {     return position;   }    @Override   public View getView(int position, View convertView, ViewGroup parent) {     ViewHolder holder = null;     if (convertView == null) {     // 如果是第一次顯示該頁面(要記得保存到viewholder中供下次直接從緩存中調用)       holder = new ViewHolder();       convertView = LayoutInflater.from(context).inflate(R.layout.item_test, null);       holder.tv_no = (TextView) convertView.findViewById(R.id.tv_no);       convertView.setTag(holder);     } else {       holder = (ViewHolder) convertView.getTag();     }     holder.tv_no.setText(nos.get(position));     if(nos.get(position).equals("full")){       convertView.setVisibility(View.INVISIBLE);     }else{       convertView.setVisibility(View.VISIBLE);     }     return convertView;   }         private class ViewHolder {     TextView tv_no;   } } 

 這樣我們就實現可以第一種解決方法

android,滾輪動畫,ListView實現滾輪

第二種方法,就是讓整個ListView實現循環滾動,實現的方式有很多,大家可以自行百度,我這里就通過修改adapter的getCount方法去實現,就是在getCount方法return一個很大的值,getView獲取數據的時候要模原本的數組大小,不然數組就越界了。然后ListView滾動到最中間,這樣就實現偽循環滾動了

public class MainActivity extends AppCompatActivity {   XuListView mLisetview;   MyAdapter adapter;   ArrayList<String> nos = new ArrayList<String>();   @Override   protected void onCreate(Bundle savedInstanceState) {     super.onCreate(savedInstanceState);     setContentView(R.layout.activity_main);      mLisetview = (XuListView) findViewById(R.id.list_test);      ArrayList<String> temp = new ArrayList<String>();     for(int i = 0;i<10;i++){       temp.add(i+"");     }     adapter = new MyAdapter(this,temp);     mLisetview.setAdapter(adapter);     //滾動到中間     mLisetview.setSelection(adapter.getCount()/2);   }  } 
/**  * Created by xu on 2017/6/27.  */ public class MyAdapter extends BaseAdapter {    ArrayList<String> nos = new ArrayList<String>();   private Context context;    public MyAdapter(Context context, ArrayList<String> nos){     this.context = context;     this.nos = nos;   }   @Override   public int getCount() {     return Integer.MAX_VALUE;   }    @Override   public Object getItem(int position) {     return nos.get(position);   }    @Override   public long getItemId(int position) {     return position;   }    @Override   public View getView(int position, View convertView, ViewGroup parent) {     ViewHolder holder = null;     if (convertView == null) {     // 如果是第一次顯示該頁面(要記得保存到viewholder中供下次直接從緩存中調用)       holder = new ViewHolder();       convertView = LayoutInflater.from(context).inflate(R.layout.item_test, null);       holder.tv_no = (TextView) convertView.findViewById(R.id.tv_no);       convertView.setTag(holder);     } else {       holder = (ViewHolder) convertView.getTag();     }     holder.tv_no.setText(nos.get(position%nos.size()));     return convertView;   }     private class ViewHolder {     TextView tv_no;   } } 

這樣我們就實現了使列表進行循環滾動,從而達到每個item都可以滾動到中間突出顯示的效果了

android,滾輪動畫,ListView實現滾輪

既然我們把動畫效果都做出來了,那么也可以直接做成一個滾輪選擇器,只需要加多兩步:1、把最靠近中間的item滾動到中間;2、把中間的item的序號通過一個接口返回出去。 我就直接貼代碼吧,反正也不難。

把最靠近中間的item滾動到中間的實現我是這么做的:首先決定好整個ListView可視的的item數量是多少,必須是奇數,這樣才能只有一個item處于正中間,然后根據ListView的高度計算出每個item符合要求的高度,然后更改現有的item的高度,同時對內容進行縮放(不縮放內容單純高度變小的話布局就亂了)。最后我們利用smoothScrollToPosition方法回正可視item中的第一個item,就實現了將最中間的item回滾到最中間的效果了。因為可視的item我們是根據ListView的高度去計算item的高度的,所有的可視item剛好鋪滿ListView,所以只要頂部那個回正了,其他的item也會回正。所以我們可以重寫一下OnScrollListener的onScrollStateChanged方法,每次滾動結束就執行一次回滾

/**  * 可視的item數  */ private int mVisibleItemCount = -1; /**  * 沒調整之前每個item的高度  */ private float olditemheight = 0; /**  * 調整過后的每個item的高度  */ private float newitemheight = -1;  /**  * 調整每個可視的item的高度 以及對內容進行縮放  */ public void reSetItemHeight() {   for (int i = 0; i < getChildCount(); i++) {     //獲取item     View temp_view = getChildAt(i);     //設置item的高度     ViewGroup.LayoutParams lp = temp_view.getLayoutParams();     lp.height = (int) newitemheight;     temp_view.setLayoutParams(lp);      //縮放內容 我的item的內容用一個LinearLayout包了起來 所以直接縮放LinearLayout     LinearLayout item_ll_value = (LinearLayout) temp_view.findViewById(R.id.item_ll_value);     item_ll_value.setScaleY((newitemheight / olditemheight) < 0 ? 0 : (newitemheight / olditemheight));     item_ll_value.setScaleX((newitemheight / olditemheight) < 0 ? 0 : (newitemheight / olditemheight));   } } /**  * 計算在給定的可視item數目下 每個item應該設置的高度  * */ private void getNewItemHeight() {   //先把舊的item存起來   olditemheight = getChildAt(0).getHeight();   //計算新的高度   newitemheight = getHeight() / mVisibleItemCount;   if ((getHeight() / mVisibleItemCount) % newitemheight > 0) {     //除不盡的情況下把余數分給各個item,暫時發現分一次余數就夠了,如果效果不理想就做個遞歸多分幾次     float remainder = (getHeight() / mVisibleItemCount) % newitemheight;     newitemheight = remainder / mVisibleItemCount;    } }  @Override public void onScrollStateChanged(AbsListView view, int scrollState) {    //滾動結束之后開始回滾item   if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE && mVisibleItemCount != -1) {     //使離中間最近的item回滾到中點位置     smoothScrollToPosition(getFirstVisiblePosition());   }  } 

實現了把最靠近中間的item滾動到中間,那么選擇的item就是滾動結束后處于最中間的item。對此我們需要再次重寫一下OnScrollListener的onScrollStateChanged方法。每次滾動結束后,取可視item中的第一個item的序號加上我們之前設置的可視item數的一半(舍去小數部分)就是最中間的item的序號了,也是當前選擇項的序號。

/**    * 當前選中項發生變化的監聽者    */   private onSelectionChangeLisenter selectionChangeLisenter;       /**    * 設置選中項的監聽者    */   public void setSelectionChangeLisenter(onSelectionChangeLisenter selectionChangeLisenter) {     this.selectionChangeLisenter = selectionChangeLisenter;   }      @Override   public void onScrollStateChanged(AbsListView view, int scrollState) {       //滾動結束之后開始正常回滾item并記錄最中間的item為選中項 (必須設置可視項,ListView才會改為選擇器模式)     if( scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE && mVisibleItemCount != -1){       //使離中間最近的item回滾到中點位置       smoothScrollToPosition(getFirstVisiblePosition());       //計算當前選中項的序號       int nowPosition = getFirstVisiblePosition() + mVisibleItemCount/2;       //把當前選中項的序號存起來并通過listener回調出去       if(selectionChangeLisenter != null && nowPosition != curPosition){         curPosition = nowPosition;         selectionChangeLisenter.onSelectionChange(curPosition);       }     }    } 

此處我是使用了一個接口去,用以實時把最新的數據返回出去

/**  * Created by xu on 2017/3/3.  */ public interface onSelectionChangeLisenter {   void onSelectionChange(int position); } 

使用這個滾輪選擇器的方法也非常簡單,除了跟正常的ListView初始化和綁定adapter之外,只需要額外調用兩個方法就行了

//設置ListView的可視item數(必須是奇數)     mLisetview.setVisibleItemCount(3); 
//設置監聽者監聽選中項的變化     mLisetview.setSelectionChangeLisenter(new onSelectionChangeLisenter() {       @Override       public void onSelectionChange(final int position) {         mHandler.post(new Runnable() {           @Override           public void run() {             Toast.makeText(MainActivity.this,"選擇項發生變化 當前選中序號:"+(temp.get(position)),Toast.LENGTH_SHORT).show();           }         });       }     }); 

這樣我們就實現滾輪數字選擇器的效果了

android,滾輪動畫,ListView實現滾輪

現在貼下整個滾輪選擇器的完整代碼

/**  * 模仿滾輪動畫縮放的ListView  * Created by xu on 2017/3/3.  */ public class XuListView extends ListView implements AbsListView.OnScrollListener {   private static final String TAG = "XuListView";    /**    * 中點的Y坐標    */   private float centerY = 0f;   /**    * 可視的item數    */   private int mVisibleItemCount = -1;   /**    * 沒調整之前每個item的高度    */   private float olditemheight = 0;   /**    * 調整過后的每個item的高度    */   private float newitemheight = -1;   /**    * 當前選中項發生變化的監聽者    */   private onSelectionChangeLisenter selectionChangeLisenter;   /**    * 當前選中項的序號    */   private int curPosition = -1;    public XuListView(Context context, AttributeSet attrs) {     super(context, attrs);     //設置一個滾動監聽     setOnScrollListener(this);   }    /**    * 設置選中項的監聽者    */   public void setSelectionChangeLisenter(onSelectionChangeLisenter selectionChangeLisenter) {     this.selectionChangeLisenter = selectionChangeLisenter;   }    /**    * 設置ListView的顯示item數    * @param count :必須是奇數  如果為-1 則表示只是使用動畫效果的普通ListView    */   public boolean setVisibleItemCount(int count){     if(count % 2 == 0){       return false;     }else{       mVisibleItemCount = count;       return true;     }    }    /**    * 在這里第一次調整item高度    */   @Override   public void onWindowFocusChanged(boolean hasWindowFocus) {     super.onWindowFocusChanged(hasWindowFocus);     if(mVisibleItemCount != -1){       getNewItemHeight();       reSetItemHeight();     }   }    /**    * 調整每個可視的item的高度 以及對內容進行縮放    */   public void reSetItemHeight(){     for(int i = 0; i < getChildCount(); i++){       //獲取item       View temp_view = getChildAt(i);       //設置item的高度       ViewGroup.LayoutParams lp = temp_view.getLayoutParams();       lp.height = (int)newitemheight;       temp_view.setLayoutParams(lp);        //縮放內容 我的item的內容用一個LinearLayout包了起來 所以直接縮放LinearLayout       LinearLayout item_ll_value = (LinearLayout)temp_view.findViewById(R.id.item_ll_value);       item_ll_value.setScaleY((newitemheight / olditemheight) < 0 ? 0 : (newitemheight / olditemheight));       item_ll_value.setScaleX((newitemheight / olditemheight) < 0 ? 0 : (newitemheight / olditemheight));     }   }     /**    * 計算在給定的可視item數目下 每個item應該設置的高度    */   private void getNewItemHeight(){     //先把舊的item存起來     olditemheight = getChildAt(0).getHeight();     //計算新的高度     newitemheight = getHeight()/mVisibleItemCount;     if((getHeight()/mVisibleItemCount) % newitemheight > 0){       //除不盡的情況下把余數分給各個item,暫時發現分一次余數就夠了,如果效果不理想就做個遞歸多分幾次       float remainder = (getHeight()/mVisibleItemCount) % newitemheight;       newitemheight = remainder/mVisibleItemCount;     }   }      @Override   public void onScrollStateChanged(AbsListView view, int scrollState) {       //滾動結束之后開始正常回滾item并記錄最中間的item為選中項 (必須設置可視項,ListView才會改為選擇器模式)     if( scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE && mVisibleItemCount != -1){       //使離中間最近的item回滾到中點位置       smoothScrollToPosition(getFirstVisiblePosition());       //計算當前選中項的序號       int nowPosition = getFirstVisiblePosition() + mVisibleItemCount/2;       //把當前選中項的序號存起來并通過listener回調出去       if(selectionChangeLisenter != null && nowPosition != curPosition){         curPosition = nowPosition;         selectionChangeLisenter.onSelectionChange(curPosition);       }     }        }    @Override   public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {     //計算中點     centerY = getHeight()/2;     //判斷中點的有效性     if(centerY <= 0){       return;     }     //開始對當前顯示的View進行縮放     for(int i = 0; i < visibleItemCount; i++){       //獲取item       View temp_view = getChildAt(i);       //計算item的中點Y坐標       float itemY = temp_view.getBottom()-(temp_view.getHeight()/2);       //計算離中點的距離       float distance = centerY;       if(itemY > centerY){         distance = itemY - centerY;       }else{         distance = centerY - itemY;       }        //根據距離進行縮放       temp_view.setScaleY(1.1f - (distance / centerY) < 0 ? 0 : 1.1f - (distance / centerY));       temp_view.setScaleX(1.1f - (distance / centerY) < 0 ? 0 : 1.1f - (distance / centerY));       //根據距離改變透明度       temp_view.setAlpha(1.1f - (distance / centerY) < 0 ? 0 : 1.1f - (distance / centerY));     }   }  } 

注釋很詳細 相信小白看了也沒什么難度。

滾輪效果的實現方式有很多,解決頭尾兩個item無法滾動到中間的方法也很多,我說的方法僅供參考,沒有最好的方法,只有最符合自己的需求的方法。

demo下載地址

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網。


注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 延庆县| 华亭县| 浙江省| 通山县| 凌海市| 蓬溪县| 汪清县| 福鼎市| 孟州市| 马边| 延庆县| 景东| 宁乡县| 峨山| 古交市| 彰化县| 临沂市| 贺州市| 象山县| 堆龙德庆县| 柞水县| 大港区| 寻乌县| 荣昌县| 楚雄市| 南郑县| 孝感市| 虞城县| 安仁县| 盱眙县| 永嘉县| 当雄县| 丹巴县| 凌海市| 蕲春县| 邹城市| 谢通门县| 兴义市| 苍溪县| 鹤岗市| 北票市|