D8-Android自定義控制元件之DotNum及item複用問題
零、前言
今天寫了一個圓點數字控制元件,效果如下:
最主要是想借此講一下關於ListView,或RecyclerView的複用問題。
本案例在圖片選擇中測試,有時間會把我的圖形選擇小專案寫一下,現在先看這個小控制元件吧。
本控制元件繪圖部分使用我的 ofollow,noindex">LogicCanvas繪相簿:基礎使用在此 , 喜歡的話可以到 github 上看看,順便給個star
支援屬性依次:大圓顏色,圓的高度(原生寬高無效),文字,是否選中,小圓顏色。
toly:z_Dot_BigColor="@color/cornsilk" toly:z_Dot_Height="@dimen/dp_56" toly:z_Dot_text="H" toly:z_Dot_isChecked="false" toly:z_Dot_SmallColor="@color/small_circle"

效果圖.gif
一、繪製
1.繪製思路:大圓+小圓+文字+狀態控制
成員變數
/** * 大圓高 */ private float mBigHeight = dp2px(20); /** * 大圓顏色 */ private int mBigCircleColor = 0x88000000; /** * 小圓顏色 */ private int mCenterColor = 0x885DFBF9; /** * 文字 */ private String mText = ""; /** * 是否選中 */ private boolean isChecked;
自定義屬性
<!--圓點數字自定義控制元件--> <declare-styleable name="DotNumView"> <!--自定義屬性名 和 型別--> <attr name="z_Dot_Height" format="dimension"/> <attr name="z_Dot_text" format="string"/> <attr name="z_Dot_BigColor" format="reference|color"/> <attr name="z_Dot_SmallColor" format="reference|color"/> <attr name="z_Dot_isChecked" format="boolean"/> </declare-styleable>
mBigHeight = ta.getDimension(R.styleable.DotNumView_z_Dot_Height, mBigHeight); mBigCircleColor = ta.getColor(R.styleable.DotNumView_z_Dot_BigColor, mBigCircleColor); mCenterColor = ta.getColor(R.styleable.DotNumView_z_Dot_SmallColor, mCenterColor); mText = ta.getString(R.styleable.DotNumView_z_Dot_text); isChecked = ta.getBoolean(R.styleable.DotNumView_z_Dot_isChecked, false); ta.recycle();//一定記得回收!!!
繪製
//獲取繪畫者 Painter painter = PainterEnum.INSTANCE.getInstance(canvas); float R = mBigHeight / 2; if (isChecked) {//選中狀態繪製 painter.draw(sa.deepClone().r(R).ang(360).p(R, -R).fs(mCenterColor)); painter.drawText(st.deepClone() .size((int) (0.6 * mBigHeight)).str(mText) .p(R, R + (int) (0.2 * mBigHeight)).fs(Color.WHITE)); } else {//未中狀態繪製 painter.draw(sa.deepClone().r(R).ang(360).p(R, -R).fs(mBigCircleColor)); painter.draw(sa.deepClone().r((float) (0.3 * R)).ang(360).p(R, -R).fs(mCenterColor)); }
測量:取大圓高
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension((int) mBigHeight, (int) mBigHeight); }
更新檢視方法:
//屬性的get、set方法略 /** * 更新檢視 * @param text 文字 * @param checked 是否選中 */ public void update(String text, boolean checked) { mText = text; this.isChecked = checked; invalidate(); }
二、使用:在介面卡中獲取item的佈局時使用
//獲取ImageView final ImageView itemIv = holder.getView(R.id.id_iv_photo); //獲取DotNumView final DotNumView dotNum = holder.getView(R.id.id_dot_check); //設定預設圖片 itemIv.setImageResource(R.drawable.no_photo); //加點灰 itemIv.setColorFilter(Color.parseColor("#11000000")); //載入圖片 final String filePath = currentDir + File.separator + data; //通過檔案路徑載入圖片 ImageLoader.getInstance(3, ImageLoader.Type.LIFO).loadImage(mContext, filePath, itemIv);
//點選選中,新增遮罩 itemIv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) {//已被選擇 //如果資料夾包含了路徑 if (mSelectedImg.contains(filePath)) { unSelect();//移除選中 } else { select();//選中 } mTvSelectCount.setText("已選" + mSelectedImg.size() + "張"); } /** * 選中時的操作 */ private void select() { //如果選中的小於9個 if (mSelectedImg.size() < 9) { //將選中的filePath加入集合 mSelectedImg.add(filePath); //更新dotNum的狀態 dotNum.update(mSelectedImg.size() + "", true); //item背景加深灰 itemIv.setColorFilter(Color.parseColor("#77000000")); } else { //否則警告 String alert = ResUtils.getString(mCtx, R.string.select_max_count); Toast.makeText(mCtx, alert, Toast.LENGTH_SHORT).show(); } } /** * 移除選中的操作 */ private void unSelect() { mSelectedImg.remove(filePath); itemIv.setColorFilter(Color.parseColor("#22000000")); dotNum.update(mSelectedImg.size() + "", false); mTvSelectCount.setText("已選" + mSelectedImg.size() + "張"); } });
三、複用問題的解決方法:
百度了幾個說得雲裡霧裡,不太明白。仔細想一下,還是發揮自己的聰明才智吧
思路:用一個Map裝一下選中的點和對應的數字,佈局載入是動態判斷一下,是否是該position的點,然後更新狀態
一開始用List,然後發現需要兩個欄位,才改成Map
一開始聲明後在獲取item佈局時才初始化map,怎麼搞的都不對,然後想想--這是不對的
1.新建mCheckedMap
private Map mCheckedMap = new HashMap<Integer, Integer>();
2.動態恢復
//所有dotNum更新到狀態 dotNum.update("", false); //檢查mCheckedMap,動態回覆狀態 if (mCheckedMap.containsKey(position)) { L.d("position:" + position + L.l()); dotNum.update(mCheckedMap.get(position)+"", true); itemIv.setColorFilter(Color.parseColor("#77000000")); }
3.選中加入Map
mCheckedMap.put(position, mSelectedImg.size());
4.不選了從Map移除
mCheckedMap.remove(position);
對於任何複用問題都可以使用這種思路來解決,好了,就到這裡
後記、
1.宣告:
[1]本文由張風捷特烈原創,轉載請註明
[2]歡迎廣大程式設計愛好者共同交流
[3]個人能力有限,如有不正之處歡迎大家批評指證,必定虛心改正
[4]你的喜歡與支援將是我最大的動力
2.連線傳送門:
更多安卓技術歡迎訪問:安卓技術棧 我的github地址:歡迎star 張風捷特烈個人網站,程式設計筆記請訪問: http://www.toly1994.com
3.聯絡我
QQ:1981462002
微信:zdl1994328
4.歡迎關注我的微信公眾號,最新精彩文章,及時送達:

公眾號.jpg