• D8-Android自定义控件之DotNum及item复用问题


    零、前言

    今天写了一个圆点数字控件,效果如下:
    最主要是想借此讲一下关于ListView,或RecyclerView的复用问题。
    本案例在图片选择中测试,有时间会把我的图形选择小项目写一下,现在先看这个小控件吧。
    本控件绘图部分使用我的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"
    
    9414344-e814d66b0d9192b2.gif
    效果图.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
    邮箱:1981462002@qq.com
    微信:zdl1994328

    4.欢迎关注我的微信公众号,最新精彩文章,及时送达:
    9414344-c474349cd3bd4b82.jpg
    公众号.jpg
  • 相关阅读:
    【Azure Redis 缓存】使用Azure Redis服务时候,如突然遇见异常,遇见命令Timeout performing SET xxxxxx等情况,如何第一时间查看是否有Failover存在呢?
    【Azure Redis 缓存】Azure Redis出现了超时问题后,记录一步一步的排查出异常的客户端连接和所执行命令的步骤
    【Azure Developer】Azure REST API: 如何通过 API查看 Recovery Services Vaults(恢复保管库)的备份策略信息? 如备份中是否含有虚拟机的Disk
    【Azure Redis 缓存】云服务Worker Role中调用StackExchange.Redis,遇见莫名异常(RedisConnectionException: UnableToConnect on xxx 或 No connection is available to service this operation: xxx)
    【Azure 环境】Azure通知中心(Notification Hub)使用百度推送平台解说
    【Azure 应用服务】Azure Function App使用SendGrid发送邮件遇见异常消息The operation was canceled,分析源码渐入最源端
    客户案例:敏捷转型的二三事儿
    从科学管理到丰田生产模式,精益是如何产生的?
    业务降本增效,数字化转型有妙招
    规模化敏捷 LeSS(三):LeSS Huge 是怎样炼成的?
  • 原文地址:https://www.cnblogs.com/toly-top/p/9781881.html
Copyright © 2020-2023  润新知