Android自定义View实战---圆盘温度计,2024年最新Android高级工程师进阶学习】

	linePaint.setAntiAlias(true);

	linePaint.setStrokeWidth(1.0f);



	textPaint = new Paint();

	textPaint.setColor(Color.BLACK);

	textPaint.setTextAlign(Paint.Align.CENTER);

	textPaint.setAntiAlias(true);

	textPaint.setTextSize(30);



	centerTextPaint = new Paint();

	centerTextPaint.setColor(Color.BLUE);

	centerTextPaint.setTextAlign(Paint.Align.CENTER);

	centerTextPaint.setAntiAlias(true);

	centerTextPaint.setTextSize(80);

	

	circlePaint = new Paint();

	circlePaint.setColor(Color.WHITE);

	circlePaint.setAntiAlias(true);

	circlePaint.setStyle(Paint.Style.STROKE);

	circlePaint.setStrokeCap(Cap.ROUND);//实现末端圆弧

	circlePaint.setStrokeWidth(60.0f);

	

	indicatorPaint=new Paint();

	indicatorPaint.setColor(0xFFF7F709);

	indicatorPaint.setAntiAlias(true);

	indicatorPaint.setStyle(Paint.Style.FILL);

	

	// 着色的共有270度,这里设置了12个颜色均分360度s

	int[] colors = { 0xFFD52B2B, 0xFFf70101, 0xFFFFFFFF, 0xFFFFFFFF,

			0xFF6AE2FD, 0xFF8CD0E5, 0xFFA3CBCB, 0xFFD1C299, 0xFFE5BD7D,

			0xFFAA5555, 0xFFBB4444, 0xFFC43C3C };

	

	mCenter = screenWidth / 2;

	mRadius = screenWidth/ 2 - 100;

	// 渐变色

	mSweepGradient = new SweepGradient(mCenter, mCenter, colors, null);

	// 构建圆的外切矩形

	mRectF = new RectF(mCenter - mRadius, mCenter - mRadius, mCenter

			+ mRadius, mCenter + mRadius);

}



1)圆环设计的宽度为wrap\_content,故需要重写onMeasure方法,告诉画笔它的外接圆矩形的宽度



// 因为自定义的空间的高度设置的是wrap_content,所以我们必须要重写onMeasure方法去测量高度,否则布局界面看不到

// 其他控件(被覆盖)

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

	setMeasuredDimension(measureWidth(widthMeasureSpec),

			measureHeight(heightMeasureSpec));

}

测量方法



/**

 * 测量宽度

 *

 * @param widthMeasureSpec

 * @return

 */

private int measureWidth(int widthMeasureSpec) {

	int mode = MeasureSpec.getMode(widthMeasureSpec);

	int size = MeasureSpec.getSize(widthMeasureSpec);

	// 默认宽高;

	defaultValue=screenWidth;

	

	switch (mode) {

	case MeasureSpec.AT_MOST:

		// 最大值模式 当控件的layout_Width或layout_height属性指定为wrap_content时

		Log.e("cmos---->", "size " + size + " screenWidth " + screenWidth);

		size = Math.min(defaultValue, size);

		break;

	case MeasureSpec.EXACTLY:

		// 精确值模式

		// 当控件的android:layout_width=”100dp”或android:layout_height=”match_parent”时



		break;

	default:

		size = defaultValue;

		break;

	}

	defaultValue = size;

	return size;

}

  

圆环的外接矩形



            mCenter = screenWidth / 2;//圆心坐标

	mRadius = screenWidth/ 2 - 100;//圆的半径  留了100dp,是为了给绘制文字留空间



	// 构建圆的外切矩形

	mRectF = new RectF(mCenter - mRadius, mCenter - mRadius, mCenter+ mRadius, mCenter + mRadius);

        canvas.drawArc(mRectF, 135, 270, false, circlePaint);

这样,圆环就绘制计算完成。



  



2)刻度值的计算绘制



因为整个圆盘是270度,设置每3度画一刻度线,故要绘制90根,这里选择的是以圆盘正上方的刻度线为基准刻度,将其绘制好后,然后进行旋转绘制,这样绘制过程就Ok了



            for (int i = 0; i < 120; i++) {

		if (i <= 45 || i >= 75) {//空白部分不用绘制刻度

			canvas.drawLine(mCenter, mCenter - mRadius - 30, mCenter,

					mCenter - mRadius + 30, linePaint);//30是因为设置的填充圆环的宽度为60的原因

		}

		canvas.rotate(3, mCenter, mCenter);

	}



  



3)圆盘刻度值计算绘制



这个就稍微复杂一点了,不过也还好,计算过程无非就是高中三角值公式的使用过程,在此之前,你先要了解角度的起始值和象限。



![](https://img-blog.csdn.net/20160730192029110?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)  

  

其中黄线的长度即是圆环的半径



	// x代表文字的x轴距离圆心x轴的距离 因为刚好是45度,所以文字x轴值和y值相等

	int x = 0;

	// 三角形的斜边

	int c = mRadius + 60 / 2 + 40;// 40代表这个字距离圆外边的距离</span>

	// 因为是每45度写一次文字,故根据到圆心的位置,利用三角形的公式,可以算出文字的坐标值

	x = (int) Math.sqrt((c * c / 2));

	canvas.drawText("10", mCenter - x, mCenter + x, textPaint);

	canvas.drawText("15", mCenter - c, mCenter,

			textPaint);

	canvas.drawText("20", mCenter - x, mCenter - x,

			textPaint);

	canvas.drawText("25", mCenter, mCenter - c,

			textPaint);

	canvas.drawText( "30", mCenter + x, mCenter - x,

			textPaint);

	canvas.drawText( "35", mCenter + c, mCenter,

			textPaint);

	canvas.drawText( "40", mCenter + x, mCenter + x,

			textPaint);

  

可以看出,这里刻度值我把它写死了,当然,你也可以暴露一个方法,让调用者去设置起始值和结束值。



  



4)中间的小圆点指示器



了解了文字的计算过程后,再来算这个的画,就相对容易了很多。  

  



       currentScanDegree=(getCurrentDegree()-10)*3;

int insideIndicator=mRadius-60;//离圆环的距离

    if (currentScanDegree<=45) {//第三象限

    	canvas.drawCircle((float)(mCenter-insideIndicator*Math.sin(Math.PI*(currentScanDegree+45)/180)),(float)(mCenter+insideIndicator*Math.cos(Math.PI*(currentScanDegree+45)/180)), 10, indicatorPaint);

	}else if(45<currentScanDegree&¤tScanDegree<=135) {//第二象限

		canvas.drawCircle((float)(mCenter-insideIndicator*Math.cos(Math.PI*(currentScanDegree-45)/180)),(float)(mCenter-insideIndicator*Math.sin(Math.PI*(currentScanDegree-45)/180)), 10, indicatorPaint);

	}else if (135<currentScanDegree&¤tScanDegree<=225) {//第一象限

		canvas.drawCircle((float)(mCenter+insideIndicator*Math.sin(Math.PI*(currentScanDegree-135)/180)),(float)(mCenter-insideIndicator*Math.cos(Math.PI*(currentScanDegree-135)/180)), 10, indicatorPaint);

	}else if(225<currentScanDegree&¤tScanDegree<=270){//第四象限

		canvas.drawCircle((float)(mCenter+insideIndicator*Math.cos(Math.PI*(currentScanDegree-225)/180)),(float)(mCenter+insideIndicator*Math.sin(Math.PI*(currentScanDegree-225)/180)), 10, indicatorPaint);

	}

过程也就不解释了,同3的过程一致



  

5)中间文字的具体温度值



   这个是根据扫描的角度值进行换算的



canvas.drawText((currentScanDegree/9+10)+“℃”, mCenter, mCenter, centerTextPaint);




相信了解了上面的过程,这个就很简单了吧。



  



到此整个计算过程就全部完成了。



  



那么,怎么让我们的view动起来呢,有点动态感,对此,我们只要不断的改变扫描的度数就好,对此我设定了3个值,最低温度值(起始)、最高温度值(结束)、当前温度。



点击按钮让其重绘。具体代码如下



private void showDegree(final int minDegree, final int maxDegree, final int currentDegree) {

	myCircleView.setMinDegree(minDegree);

	new Thread(new Runnable() {

		

		@Override

		public void run() {

			for (int i = minDegree; i < (maxDegree-minDegree)*3+minDegree; i++) {

				try {

					Thread.sleep(30);

				} catch (InterruptedException e) {

					// TODO 自动生成的 catch 块

					e.printStackTrace();

				}

				

				myCircleView.setMaxDegree(i);

				myCircleView.postInvalidate();

			}

			for (int j = 10; j<=(currentDegree-10)*3+10; j++) {

				if (j<=(currentDegree-10)*3+10) {//23*3+10=79

					myCircleView.setCurrentDegree(j);

				}

				myCircleView.postInvalidate();

			}

		}

	}).start();

}


  

上面要注意的地方是要注意使用postInvalidata()方法,因为我们是在子线程操控UI线程,所以不能单纯的用invalidata()方法。



  



**3\. view添加滑动触摸事件**



最后作为扩展,我为此控件添加了滑动触摸事件



代码如下:



@Override

public boolean onTouchEvent(MotionEvent event) {

	// TODO 自动生成的方法存根

	switch (event.getAction()) {

	case MotionEvent.ACTION_DOWN:

		isCanMove = true;

		break;

	case MotionEvent.ACTION_MOVE:

		float x = event.getX();

		float y = event.getY();

		float StartX = event.getX();

		float StartY = event.getY();

		// 判断当前手指距离圆心的距离 如果大于mCenter代表在圆心的右侧

		if (x > mCenter) {

			x = x - mCenter;

		} else {

			x = mCenter - x;

		}

		if (y > mCenter) {

			y = y - mCenter;

		} else {

			y = mCenter - y;

		}

		// 判断当前手指是否在圆环上的(30+10多加了10个像素)

		if ((mRadius + 40) < Math.sqrt(x * x + y * y)

				|| Math.sqrt(x * x + y * y) < (mRadius - 40)) {

			Log.e("cmos---->", "终止滑动");

			isCanMove = false;

			return false;

		}

		float cosValue = x / (float) Math.sqrt(x * x + y * y);

		// 根据cosValue求角度值

		double acos = Math.acos(cosValue);// 弧度值

		acos = Math.toDegrees(acos);// 角度值



		if (StartX > mCenter && StartY < mCenter) {

			acos = 360 - acos;// 第一象限

			Log.e("象限---->", "第一象限");

		} else if (StartX < mCenter && StartY < mCenter) {

			acos = 180 + acos;// 第二象限

			Log.e("象限---->", "第二象限");

		} else if (StartX < mCenter && StartY > mCenter) {

			acos = 180 - acos;// 第三象限

			Log.e("象限---->", "第三象限");

		} else {

			// acos=acos;

			Log.e("象限---->", "第四象限");

		}

		Log.e("旋转的角度---->", acos + "");

		scanDegree = (int) acos;

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
img

学习分享

在当下这个信息共享的时代,很多资源都可以在网络上找到,只取决于你愿不愿意找或是找的方法对不对了

很多朋友不是没有资料,大多都是有几十上百个G,但是杂乱无章,不知道怎么看从哪看起,甚至是看后就忘

如果大家觉得自己在网上找的资料非常杂乱、不成体系的话,我也分享一套给大家,比较系统,我平常自己也会经常研读。

2021最新上万页的大厂面试真题

image

七大模块学习资料:如NDK模块开发、Android框架体系架构…

image

2021大厂面试真题:

image

只有系统,有方向的学习,才能在短时间内迅速提高自己的技术,只有不断地学习,不懈的努力才能拥有更好的技术,才能在互联网行业中立于不败之地。

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img
)]

学习分享

在当下这个信息共享的时代,很多资源都可以在网络上找到,只取决于你愿不愿意找或是找的方法对不对了

很多朋友不是没有资料,大多都是有几十上百个G,但是杂乱无章,不知道怎么看从哪看起,甚至是看后就忘

如果大家觉得自己在网上找的资料非常杂乱、不成体系的话,我也分享一套给大家,比较系统,我平常自己也会经常研读。

2021最新上万页的大厂面试真题

[外链图片转存中…(img-5OErinA9-1712779255178)]

七大模块学习资料:如NDK模块开发、Android框架体系架构…

[外链图片转存中…(img-OUR1bIGc-1712779255178)]

2021大厂面试真题:

[外链图片转存中…(img-UO3MvD5b-1712779255178)]

只有系统,有方向的学习,才能在短时间内迅速提高自己的技术,只有不断地学习,不懈的努力才能拥有更好的技术,才能在互联网行业中立于不败之地。

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-H80ZaHOP-1712779255179)]

  • 17
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面我来为您讲解如何在Android Studio中实现备忘录应用的开发。 首先,我们需要创建一个新的Android Studio项目。在创建项目时,您可以选择空白活动或使用模板(例如带有导航抽屉的活动)。在这里,我们将使用空白活动来创建我们的备忘录应用。 接下来,我们需要设计应用的用户界面。我们将使用RecyclerView来显示备忘录列表,并且使用一个FloatingActionButton来添加新的备忘录。使用Android Studio的布局编辑器,您可以轻松地设计出这个用户界面。 在我们开始编写代码之前,我们需要添加RecyclerView和FloatingActionButton的依赖库。在app/build.gradle文件中,添加以下依赖项: ``` dependencies { implementation 'com.android.support:recyclerview-v7:28.0.0' implementation 'com.android.support:design:28.0.0' } ``` 接下来,我们需要创建一个备忘录数据模型类Memo,该类将具有备忘录的标题和内容属性。例如: ``` public class Memo { private String title; private String content; public Memo(String title, String content) { this.title = title; this.content = content; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } } ``` 接下来,我们需要创建一个备忘录列表适配器MemoAdapter,该适配器将显示备忘录列表。例如: ``` public class MemoAdapter extends RecyclerView.Adapter<MemoAdapter.ViewHolder> { private List<Memo> memos; public MemoAdapter(List<Memo> memos) { this.memos = memos; } @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_memo, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { Memo memo = memos.get(position); holder.titleTextView.setText(memo.getTitle()); holder.contentTextView.setText(memo.getContent()); } @Override public int getItemCount() { return memos.size(); } public class ViewHolder extends RecyclerView.ViewHolder { private TextView titleTextView; private TextView contentTextView; public ViewHolder(View itemView) { super(itemView); titleTextView = itemView.findViewById(R.id.titleTextView); contentTextView = itemView.findViewById(R.id.contentTextView); } } } ``` 接下来,我们需要创建一个活动MainActivity,该活动将显示备忘录列表。在MainActivity中,我们需要将RecyclerView与MemoAdapter进行绑定,并在FloatingActionButton的单击事件中添加新的备忘录。例如: ``` public class MainActivity extends AppCompatActivity { private List<Memo> memos = new ArrayList<>(); private MemoAdapter memoAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); RecyclerView recyclerView = findViewById(R.id.recyclerView); memoAdapter = new MemoAdapter(memos); recyclerView.setAdapter(memoAdapter); recyclerView.setLayoutManager(new LinearLayoutManager(this)); FloatingActionButton fab = findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { showAddMemoDialog(); } }); } private void showAddMemoDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(this); View view = LayoutInflater.from(this).inflate(R.layout.dialog_add_memo, null); final EditText titleEditText = view.findViewById(R.id.titleEditText); final EditText contentEditText = view.findViewById(R.id.contentEditText); builder.setView(view) .setTitle("Add Memo") .setPositiveButton("Add", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { String title = titleEditText.getText().toString(); String content = contentEditText.getText().toString(); Memo memo = new Memo(title, content); memos.add(memo); memoAdapter.notifyDataSetChanged(); } }) .setNegativeButton("Cancel", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.cancel(); } }); AlertDialog dialog = builder.create(); dialog.show(); } } ``` 最后,在这个应用程序中,我们需要添加一些布局文件。例如: activity_main.xml ``` <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="4dp" /> <android.support.design.widget.FloatingActionButton android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="16dp" android:src="@drawable/ic_add" /> </android.support.design.widget.CoordinatorLayout> ``` item_memo.xml ``` <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="8dp"> <TextView android:id="@+id/titleTextView" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="24sp" android:textStyle="bold" /> <TextView android:id="@+id/contentTextView" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="18sp" /> </LinearLayout> ``` dialog_add_memo.xml ``` <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="8dp"> <EditText android:id="@+id/titleEditText" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Title" /> <EditText android:id="@+id/contentEditText" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Content" /> </LinearLayout> ``` 现在您已经完成了备忘录应用的开发。您可以在模拟器或实际设备上运行该应用程序,并开始添加和查看备忘录了!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值