效果展示

前言

前面,我讲了自定义组件的基本知识,也教了大家写了些自定义组件,相信大家对 构造函数、测量(onMeasure)及绘制(onDraw)方法了如执掌了,下面这个自定义组件,我会带大家更上一层楼,接触 人机交互事件(onTouchEvent)处理方法,面对一个新知识点,大家不要惧怕,始终要坚信,只要时间到位,没什么过不去的坎。废话不多说,上码!!!(这句话我是直接在输入法里连着打出来的,哈哈哈)

源码分析

老套路,“五步走”法

第一步:先创建自定义组件类,继承自View

第二步:创建自定义属性文件

<?xml version="1.0" encoding="utf-8"?>
<resources><declare-styleable name="RatingBar"><attr name="normalBit" format="reference"/>  //触摸前引用的资源<attr name="focusBit" format="reference"/>   //触摸后引用的资源<attr name="gradeNum" format="integer"/>     //数量</declare-styleable>
</resources>

第三步:在布局中引用

(大家不要固化思维,引用 也可以在代码里动态实现,例如:我这篇文章 Android开发-仿今日头条文字变色效果)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center"tools:context=".MainActivity"><com.wustyq.view_day06.RatingBarandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:padding="5dp"app:normalBit="@drawable/ic_half_star2"app:focusBit="@drawable/ic_un_star2"app:gradeNum="5"/></LinearLayout>

第四步:在自定义组件类中获取属性值 并编写相关方法

package com.wustyq.view_day06;import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;import androidx.annotation.Nullable;public class RatingBar extends View {private Bitmap mNormalBit;private Bitmap mFocusBit;private int mGradeNum;private int mCurrentGrade = 0;public RatingBar(Context context) {this(context,null);}public RatingBar(Context context, @Nullable AttributeSet attrs) {this(context, attrs,0);}public RatingBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RatingBar);//不能直接获取资源bitmap,所以,先获取资源 ID ,再由 BitmapFactory 转换int normalBitId = typedArray.getResourceId(R.styleable.RatingBar_normalBit, 0);if (normalBitId == 0){throw new RuntimeException("请设置属性 normalBit");}BitmapFactory.Options opts = new BitmapFactory.Options();opts.inSampleSize = 4;mNormalBit = BitmapFactory.decodeResource(getResources(),normalBitId,opts);//不能直接获取资源bitmap,所以,先获取资源 ID ,再由 BitmapFactory 转换int focusBitId = typedArray.getResourceId(R.styleable.RatingBar_focusBit, 0);if (focusBitId == 0){throw new RuntimeException("请设置属性 focusBit");}mFocusBit = BitmapFactory.decodeResource(getResources(),focusBitId,opts);mGradeNum = typedArray.getInt(R.styleable.RatingBar_gradeNum, mGradeNum);typedArray.recycle();}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);//高度 一张图片的高度 实现 padding 间隔自己根据 示意图 和下面 公式对着算int height = Math.max(mNormalBit.getHeight(),mFocusBit.getHeight()) + getPaddingTop() + getPaddingBottom();int width = Math.max(mNormalBit.getWidth(),mFocusBit.getWidth())*mGradeNum + mGradeNum * (getPaddingLeft() + getPaddingRight());setMeasuredDimension(width,height);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);//画触摸前的图片for (int i = 0; i < mGradeNum; i++) {float x = i * mNormalBit.getWidth() + (i+1)*getPaddingLeft();canvas.drawBitmap(mNormalBit,x,getPaddingTop(),null);}//画触摸后的图片for (int i = 0; i < mCurrentGrade; i++) {float x = i * mFocusBit.getWidth() + (i+1)*getPaddingLeft();canvas.drawBitmap(mFocusBit,x,getPaddingTop(),null);}}@Overridepublic boolean onTouchEvent(MotionEvent event) {System.out.println("moveX -> " + event.getAction());//按下 移动 抬起 处理逻辑都一样,判断手指的位置,根据当前位置计算分数,再去刷新switch(event.getAction()){case MotionEvent.ACTION_DOWN: //按下case MotionEvent.ACTION_MOVE: //移动
//            case MotionEvent.ACTION_UP: //抬起  优化,尽量减少onDraw(){float moveX = event.getX(); //event.getRawX()获取屏幕的x位置  event.getX()相当于控件的x位置System.out.println("moveX -> " + moveX);//计算分数float currentGrade = moveX/(mNormalBit.getWidth()+ getPaddingLeft());if (currentGrade <= 0.0f){currentGrade = 0;}else if (currentGrade > mGradeNum){currentGrade = mGradeNum;}else {currentGrade += 1;}if (currentGrade == mCurrentGrade)return true;mCurrentGrade = (int) currentGrade;invalidate(); //系统帮我们调用 onDraw() 减少onDraw()的调用 , 目前是不断调用}break;}return true;//onTouch 后面会逐步讲源码 false 代表不消费 第一次 Down false DOWN以后的事件进不来}
}

这一段代码是有点干货的,例如:

第一点:Bitmap图片的处理,inSampleSize 这个参数代表采样率  通过配置这个值可以压缩图片 如果 inSampleSize = 2 那么加载到内存中的图片 宽度是原图的1/2 高度也是原图的1/2 总的大小是原图的1/4;需要注意 如果inSampleSize < 1 会按照1来处理 解码器默认会按照2的幂指数来处理图片的压缩 所以可以传入 2的幂指数来作为 inSampleSize 的值。

第二点:如何获取并绘制 属性值为资源文件的 属性,这句话有点绕,相信各位的理解能力哈。步骤是这样的     typedArray.getResourceId() 获取资源文件id   ---->   BitmapFactory.decodeResource(getResources(),normalBitId,opts)  通过BitmapFactory解析资源文件Id获取图片Bitmap  --->  canvas.drawBitmap(mNormalBit,x,getPaddingTop(),null)  绘制图片

第三点:如何监控  padding  ,我就用一张图片来解释吧,老规矩,公式在代码里已经呈现了,图中只呈现了两个获取宽度的方法,获取高度的类似。

第五步:外面类调用

虽然,外面类里并没有写啥,但是,步骤不能少,哈哈哈。

package com.wustyq.view_day06;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}
}

代码优化

在这里,我有一点要强调的,就是当我们把代码 码完了之后,就不要认为工作做完了,我们还得回过头来看看,有没有哪些代码可以优化的,

里面有些代码已经优化了,比如 onTouchEvent() 方法里,尽量减少onDraw()方法的调用,间接的就是说减少 invalidate() 的调用,大家有时间可以执行查阅 invalidate() 源码

接下来我带着大家优化一段

没有优化前的代码

@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);//画触摸前的图片for (int i = 0; i < mGradeNum; i++) {float x = i * mNormalBit.getWidth() + (i+1)*getPaddingLeft();canvas.drawBitmap(mNormalBit,x,getPaddingTop(),null);}//画触摸后的图片for (int i = 0; i < mCurrentGrade; i++) {float x = i * mFocusBit.getWidth() + (i+1)*getPaddingLeft();canvas.drawBitmap(mFocusBit,x,getPaddingTop(),null);}}

优化之后的代码

@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);for (int i = 0; i < mGradeNum; i++) {float x1 = i * mNormalBit.getWidth() + (i+1)*getPaddingLeft();float x2 = i * mFocusBit.getWidth() + (i+1)*getPaddingLeft();if(i < mCurrentGrade){//画触摸后的图片canvas.drawBitmap(mFocusBit,x2,getPaddingTop(),null);}else {//画触摸前的图片canvas.drawBitmap(mNormalBit,x1,getPaddingTop(),null);}}}

很明显可以看出,减少了绘制的次数,提高了性能。

相信肯定有厉害的朋友一步到位了,请不要嘲笑小弟哦!!!

仿淘宝、腾讯课堂评分组件 --- Android高级自定义组件相关推荐

  1. android app实现轮播的图片视频播放video,仿淘宝商品详情的视频播放(android)

    这段时间在学习开发android app 记录一下实现仿淘宝图片视频切换的功能,直接拿来用即可,大家有什么问题可以共同交流 先看一下目录结构吧 思路: ViewPager 分别实现三个类型的滑动–fr ...

  2. iOS物理碰撞、唱吧音频处理、仿淘宝联动效果等源码

    iOS精选源码 物理仿真 碰撞 陀螺仪 使用 仿淘宝详情和每日优鲜的一个联动效果 JJNetwork网络库 iOS列表选择弹框 网络视频直播类--原生socket音视频实时传输--智能家居 Skele ...

  3. javah5仿淘宝购物系统计算机毕业设计MyBatis+系统+LW文档+源码+调试部署

    javah5仿淘宝购物系统计算机毕业设计MyBatis+系统+LW文档+源码+调试部署 javah5仿淘宝购物系统计算机毕业设计MyBatis+系统+LW文档+源码+调试部署 本源码技术栈: 项目架构 ...

  4. iOS物理碰撞、唱吧音频处理、仿淘宝联动效果等源码 1

    iOS精选源码 物理仿真 碰撞 陀螺仪 使用 仿淘宝详情和每日优鲜的一个联动效果 JJNetwork网络库 iOS列表选择弹框 网络视频直播类–原生socket音视频实时传输–智能家居 Skeleto ...

  5. java B2B2C Springcloud仿淘宝电子商城系统-spring cloud 框架原理

    我们从整体来看一下Spring Cloud主要的组件,以及它的访问流程 需要JAVA Spring Cloud大型企业分布式微服务云构建的B2B2C电子商务平台源码 一零三八七七四六二六 1.外部或者 ...

  6. 使用WEX5移动开发工具制作仿淘宝APP

    毕业设计-使用WEX5移动开发工具制作仿淘宝APP 系统设计的意义 本课题来源于对日常逛超市.购物的生活体验和指导老师的提示.本系统是基于 WeX5的仿淘宝App系统,它商家们提供了一个更广阔的商品推 ...

  7. 安卓APP源码和设计报告——仿淘宝水果商城

    项目名称 仿淘宝水果商城 项目概述 随着互联网技术地高速发展,计算机进入到每一个人的生活里,从人们的生活方式到整个社会的运转都产生了巨大的变革,而在信息技术发达的今天,互联网的各种娱乐方式都在渗透到人 ...

  8. vue仿淘宝放大镜插件 vue-piczoom的使用问题

    vue仿淘宝放大镜插件 vue-piczoom npm install vue-piczoom--save //下载放大镜插件 使用的话就是直接引入 import picZoom from 'vue- ...

  9. 基于BootStrap仿淘宝星星商品评价案例

    <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8" ...

  10. 仿淘宝电商官网静态页面(HTML+CSS+JS)+ 常见布局解析,学会如果做是关键!

    仿淘宝电商官网静态页面 作为一个前端开发,布局+样式已经成为了必备的技能,你做得好是应该的,做的不好可以原谅,但当你意识到不足时,补足它 这是我刚"入坑"的时候写的Demo,因为当 ...

最新文章

  1. 设计模式解析(五)——几种设计模式之Facade和Adapter
  2. java基础提升篇:Static关键字
  3. Groovy中转换成java,Groovy将字符串类型转换为自定义类型的方法
  4. php对联广告,html左右对联代码 cms网站对联广告html代码
  5. PullToRefresh
  6. SAP License:SAP资产管理模块中的相关业务处理
  7. 数据分析|如何利用BI工具,探索各商品的潜在关联价值
  8. 求出现重现次数最多的字母,如有多个反复的则都求出来
  9. PSP,CPS1街机模拟器终于出来了(CAPCOM CPS1 Emulators for the PSP),完美!
  10. 信号与系统公式大全(傅里叶变换、拉普拉斯变换、Z变换、卷积...)
  11. 2020大疆校招B卷第二题
  12. 顶级“黑客”能厉害到什么地步?无信号也能上网,专家:高端操作!
  13. C# Word文档中插入、提取图片,文字替换图片
  14. 用C语言计算BMI值
  15. Spring框架中的单例Bean是线程安全的么?
  16. traceroute 安装及使用
  17. 软件测试之补丁包测试
  18. 哪些关于硬件的事之串行与并行到底是hang还是xing
  19. 网络图片版权保护的主要问题
  20. java8新特性-stream对map集合进行过滤的方法

热门文章

  1. Robo3T连接远程mongodb
  2. [转]高负载并发网站架构分析
  3. MySQL Mac 终端环境变量配置
  4. matlab各种文件读写,Matlab的各种数据读取、文件读写等操作汇总
  5. git创建本地代码库
  6. idea安装阿里巴巴Java开发规范插件
  7. 如何获取每周的星期一和星期天的日期
  8. python主函数调用子函数,实现excel数据写入
  9. 什么是哑终端,终端模拟器
  10. 4.1 手工编写第一个性能测试脚本