編輯:關於Android編程
前言
相信大家都知道Android滾動控件的實現方式有很多, 使用RecyclerView也比較簡單. 做了一個簡單的年齡滾動控件, 讓我們來看看RecyclerView的使用方式, 主要有以下幾點:
(1) 對齊控件中心位置.
(2) 計算滾動距離.
(3) 高亮中心視圖.
(4) 實時顯示中心數據.
(5) 停止時自動對齊.
(6) 滾動時, 設置按鈕狀態開關.
效果
1. 框架
主要關注RecyclerView部分邏輯.
/** * 初始化年齡滑動條 */ private void initAgeList() { LinearLayoutManager mLayoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.HORIZONTAL, false); mRvAgeList.setLayoutManager(mLayoutManager); mAgeAdapter = new PersonAgeAdapter(START_NUM, END_NUM); mRvAgeList.setAdapter(mAgeAdapter); mRvAgeList.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); mBDownStep.setEnabled(false); // 效果在暫停時顯示, 否則會導致重繪異常 if (newState == RecyclerView.SCROLL_STATE_IDLE) { mAgeAdapter.highlightItem(getMiddlePosition()); mRvAgeList.scrollToPosition(getScrollPosition()); mLastValue = getMiddlePosition(); UserInfoManager.setAge(getMiddlePosition() + START_NUM); mBDownStep.setEnabled(true); // 滑動時不可用, 停止時才可以 } } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { // 值是實時增加 mTvAgeValue.setText(String.valueOf(getMiddlePosition() + START_NUM)); } }); mAgeAdapter.highlightItem(getMiddlePosition()); }
設置一個水平布局
LinearLayoutManager mLayoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.HORIZONTAL, false); mRvAgeList.setLayoutManager(mLayoutManager);
添加Adapter, 設置起始和結束位置.
mAgeAdapter = new PersonAgeAdapter(START_NUM, END_NUM); mRvAgeList.setAdapter(mAgeAdapter);
2. Adapter
Adapter定制一些功能, 如標示指向中心位置, 數據聯動顯示, 高亮Item
等.
/** * 年齡的適配器 * <p> * Created by wangchenlong on 15/11/12. */ public class PersonAgeAdapter extends RecyclerView.Adapter<PersonAgeAdapter.AgeItemViewHolder> { public static final int ITEM_NUM = 7; // 每行擁有的Item數, 必須是奇數 private int mFrom; // 起始 private int mTo; // 終止 private int mHighlight = -1; // 高亮 public PersonAgeAdapter(int from, int to) { mFrom = from; mTo = to; } @Override public AgeItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View item = LayoutInflater.from(parent.getContext()). inflate(R.layout.view_age_item, parent, false); // 設置Item的寬度 ViewGroup.LayoutParams lp = item.getLayoutParams(); lp.width = getItemStdWidth(); return new AgeItemViewHolder(item); } @Override public void onBindViewHolder(AgeItemViewHolder holder, int position) { holder.getTextView().setText(String.valueOf(mFrom + position)); // 高亮顯示 if (isSelected(position)) { holder.getTextView().setTextSize(30); holder.getTextView().setTextColor(ChunyuApp.getAppContext().getResources().getColor(R.color.black)); } else { holder.getTextView().setTextSize(20); holder.getTextView().setTextColor(ChunyuApp.getAppContext().getResources().getColor(R.color.gray_line)); } } // 高亮中心, 更新前後位置 public void highlightItem(int position) { mHighlight = position; int offset = ITEM_NUM / 2; for (int i = position - offset; i <= position + offset; ++i) notifyItemChanged(i); } // 判斷是否是高亮 public boolean isSelected(int position) { return mHighlight == position; } @Override public int getItemCount() { return mTo - mFrom + 1; } // 獲取標准寬度 public static int getItemStdWidth() { DisplayMetrics displayMetrics = ChunyuApp.getAppContext().getResources().getDisplayMetrics(); return displayMetrics.widthPixels / ITEM_NUM; } // ViewHolder public class AgeItemViewHolder extends RecyclerView.ViewHolder { private TextView mTextView; public AgeItemViewHolder(View itemView) { super(itemView); mTextView = (TextView) itemView.findViewById(R.id.item_age_value); mTextView.setTag(this); } public TextView getTextView() { return mTextView; } } }
每個單元格寬度是屏幕寬度的奇數分之一, 填充屏幕, 則起始指向中心.
@Override public AgeItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View item = LayoutInflater.from(parent.getContext()). inflate(R.layout.view_age_item, parent, false); // 設置Item的寬度 ViewGroup.LayoutParams lp = item.getLayoutParams(); lp.width = getItemStdWidth(); return new AgeItemViewHolder(item); }
單數Item
數量, 則中心的指示器必指向中心Item
的中心.
根據選中狀態, 更新Item
樣式.
@Override public void onBindViewHolder(AgeItemViewHolder holder, int position) { holder.getTextView().setText(String.valueOf(mFrom + position)); // 高亮顯示 if (isSelected(position)) { holder.getTextView().setTextSize(30); holder.getTextView().setTextColor(ChunyuApp.getAppContext().getResources().getColor(R.color.black)); } else { holder.getTextView().setTextSize(20); holder.getTextView().setTextColor(ChunyuApp.getAppContext().getResources().getColor(R.color.gray_line)); } }
設置高亮, 把中心位置高亮, 兩邊恢復, 通知Adapter重繪ViewHolder.
// 高亮中心, 更新前後位置 public void highlightItem(int position) { mHighlight = position; int offset = ITEM_NUM / 2; for (int i = position - offset; i <= position + offset; ++i) notifyItemChanged(i); } // 判斷是否是高亮 public boolean isSelected(int position) { return mHighlight == position; } notifyItemChanged()會重繪所選擇的頁面.
獲取寬度, 把一行顯示Item
數量設置為單數, 則中心指向一個Item
.
// 獲取標准寬度 public static int getItemStdWidth() { DisplayMetrics displayMetrics = ChunyuApp.getAppContext().getResources().getDisplayMetrics(); return displayMetrics.widthPixels / ITEM_NUM; }
注意RecyclerView不能移動半個單元, 每行數量是單數時, 則必會指向中心.
3. 滾動邏輯
在滾動時, 實時更新頁面顯示; 在停止時, 更新高亮和存儲數據; 滾動結束時, 激活按鈕.
mRvAgeList.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); mBDownStep.setEnabled(false); // 效果在暫停時顯示, 否則會導致重繪異常 if (newState == RecyclerView.SCROLL_STATE_IDLE) { mAgeAdapter.highlightItem(getMiddlePosition()); mRvAgeList.scrollToPosition(getScrollPosition()); mLastValue = getMiddlePosition(); UserInfoManager.setAge(getMiddlePosition() + START_NUM); mBDownStep.setEnabled(true); // 滑動時不可用, 停止時才可以 } } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { // 值是實時增加 mTvAgeValue.setText(String.valueOf(getMiddlePosition() + START_NUM)); } }); mAgeAdapter.highlightItem(getMiddlePosition()); } /** * 獲取中間位置 * * @return 當前值 */ private int getMiddlePosition() { return getScrollPosition() + (PersonAgeAdapter.ITEM_NUM / 2); } /** * 獲取滑動值, 滑動偏移 / 每個格子寬度 * * @return 當前值 */ private int getScrollPosition() { return (int) ((double) mRvAgeList.computeHorizontalScrollOffset() / (double) PersonAgeAdapter.getItemStdWidth()); }
判斷滾動的距離單位, 偏移總距離/單個Item
寬度.
private int getScrollPosition() { return (int) ((double) mRvAgeList.computeHorizontalScrollOffset() / (double) PersonAgeAdapter.getItemStdWidth()); }
computeHorizontalScrollOffset()
獲取RecyclerView的偏移總位移.
中間位置, 還要加上半行Item
數量
private int getMiddlePosition() { return getScrollPosition() + (PersonAgeAdapter.ITEM_NUM / 2); }
判斷滾動是否停止.
if (newState == RecyclerView.SCROLL_STATE_IDLE)
在滾動停止時, 自動對齊.
mRvAgeList.scrollToPosition(getScrollPosition());
調用需要高亮顯示的Item
.
mAgeAdapter.highlightItem(getMiddlePosition());
注意在滾動停止時, 更新高亮比較好, 否則重繪速度較慢, 會影響滾動效果.
滑動效果
總結
好了,以上就是這篇文章的全部內容了,我們可以根據這些定制各式各樣的滾動條了!希望這篇文章對大家能有所幫助。
Android 啟動模式: 啟動模式:LaunchMode在多個Activity跳轉的過程中扮演著重要的角色,它可以決定是否
我們先實現拍照按鈕的圓形效果哈,Android開發中,當然可以找美工人員設計圖片,然後直接拿進來,不過我們可以自己寫代碼實現這個效果哈,最常用的的是用layout-lis
上篇給大家介紹QQ5.0側滑菜單的視頻課程,對於側滑的時的動畫效果的實現有了新的認識,似乎打通了任督二脈,目前可以實現任意效果的側滑菜單了,感謝鴻洋大大!!用的是Hori
在上一篇關於ActionBar的博文中,我們知道了ActionBar是Android3.0的重要更新之一。本篇博文就來寫一個開發中經常用到的例子。用Act