android高级UI之Canvas综合案例操练

2023-10-30 09:10

本文主要是介绍android高级UI之Canvas综合案例操练,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在上一次https://www.cnblogs.com/webor2006/p/12679470.html对于Canvas的坐标系和Layer进行了学习,这次来看一个关于Canvas的综合案例,对之前的学习加以巩固,其实现也不是很简单,下面一点点来攻克它。

效果演示:

先来看一下最终的效果:

其中这个效果一般会应用于相机APP中,看一个下面从fragmentapp.com【貌似目前该网站打不开了。。】上的一个视频截图效果:

具体实现:

说实话我看到这个效果还是有点为难的,一个图片怎么能根据是否选中和未选中来显示一部分是亮色,一部分是灰色效果呢?要自定义View肯定是不用说了,其实这里面还是蕴藏很多知识点的,里面的API平常也用得比较少,下面就一步步来剖析它的实现。

先来了解Drawable的本质:

对于Drawable我们平常开发中每天都会接触到,很简单嘛它就代表一张“图”,这是从我们使用的角度来说确实是的,但是!!它是一个可画的对象,其可能是一张位图(BitmapDrawable),也有可能是一个图形,一个图层,我们根据画图的需求,创建相应的可画对象,可以理解为一个内存画布,在Drawable中有一个draw()方法:

那为啥先要了解它呢?因为要实现图片的半灰半亮的效果就需要使用自定义Drawable的技法,而它有啥有了解的呢?看下面两个问题:

1、Drawable实例到底是如何被绘制到屏幕上面的?

2、Drawable源码中的那些API方法又是什么时候被谁调用的?

此时肯定要从源码的角度来找答案了,而平常我们在获得Drawable对象时都会这样写:

所以寻找的入口就从它开始,跟进去:

Drawable实例是如何创建的?

继续往下跟:

其中ConstantState是恒定状态的意思,这里对它稍加解释一下:每个Drawable类对象类都关联有一个ConstantState类对象,这是为了保存Drawable类对象的一些恒定不变的数据,如果从同一个res中创建的Drawable类对象,为了节约内存,它们会共享同一个ConstantState类对象,比如一个ColorDrawable类对象,它会关联一个ColorState类对象,color的颜色值是保存在ColorState类对象中的。如果修改ColorDrawable的颜色值,会修改到ColorState的值,会导致和ColorState关联的所有的ColorDrawable的颜色都改变。在修改ColorDrawable的属性的时候,需要先调用public Drawable mutate()方法,让Drawable复制一个新的ConstantState对象关联。

好,继续往下:

Drawable实例如何绘制在屏幕上的?

平常显示图片我们通常会使用ImageView控件,通常会这样使用:

所以此时就从这个入口开始寻找答案:

好!!既然要看如何绘制,对于View来说肯定得瞅onDraw()方法了:

所以能过这个分析,可以看到Drawable并非是一张图片,而是它是用来加载图片的一个工具。

RevealView图形实现:

框架搭建:

咱们首先来实现一个静态图的效果,滑动的先不管,如下:

这里其实是用到了两张图片,素材如下:

所以先将它们导进来:

然后这里自定义一个Drawable,里面会持有这两个Drawable,最终再加上一些逻辑达到最终所看到的一半亮一半灰的效果,如下:

package com.paintgradient.test.canvas;import android.annotation.SuppressLint;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.Log;public class RevealDrawable extends Drawable {private Drawable mUnselectedDrawable;private Drawable mSelectedDrawable;public RevealDrawable(Drawable unselected, Drawable selected) {mUnselectedDrawable = unselected;mSelectedDrawable = selected;}@Overridepublic void draw(Canvas canvas) {}@Overrideprotected void onBoundsChange(Rect bounds) {// 定好两个Drawable图片的宽高---边界boundsmUnselectedDrawable.setBounds(bounds);mSelectedDrawable.setBounds(bounds);Log.d("cexo", "w = " + bounds.width());}@Overridepublic int getIntrinsicWidth() {//得到Drawable的实际宽度return Math.max(mSelectedDrawable.getIntrinsicWidth(),mUnselectedDrawable.getIntrinsicWidth());}@Overridepublic int getIntrinsicHeight() {//得到Drawable的实际高度return Math.max(mSelectedDrawable.getIntrinsicHeight(),mUnselectedDrawable.getIntrinsicHeight());}@Overridepublic void setAlpha(int alpha) {}@Overridepublic void setColorFilter(ColorFilter cf) {}@SuppressLint("WrongConstant")@Overridepublic int getOpacity() {return 0;}}

对于没有自定义过Drawable的对于上面的API其实也一看就明白,定义过一次之后就晓得套路了,然后咱们在布局文件中声明个ImageView:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center"tools:context=".MainActivity"><ImageViewandroid:id="@+id/imageView"android:layout_width="wrap_content"android:layout_height="wrap_content" /></LinearLayout>

然后这么来调用:

package com.paintgradient.test;import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ImageView;import com.paintgradient.test.canvas.RevealDrawable;public class MainActivity extends AppCompatActivity {private ImageView imageView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);imageView = findViewById(R.id.imageView);RevealDrawable revealDrawable = new RevealDrawable(getDrawable(R.drawable.avft), getDrawable(R.drawable.avft_active));imageView.setImageDrawable(revealDrawable);}
}

思路整理:

好,核心的核心就是如何来编写它里面的draw(Canvas canvas)方法了,其实现思路也比较简单:

 

 

也就实现了我们所要的效果:

Gravity.apply()扣图利器了解:

那么问题来了,如何能从得到的Drawable原图中进行相印的裁剪呢?这里对于Canvas来说有一个这样的API能达到裁剪的目的:

然后再让原图往这个画布上绘制既可实现图片裁剪的效果了,示例代码如下:

那么重点来了,如何来计算这个temp要显示的这个矩形区域呢?这里要用到一个平常可能用得比较少但是面对这种场景来说又非常实现的一个API了:

我猜8成以上搞Android的人应该都没用过,我也没有,所以学完这次之后对于要扣图的场景到时第一时间就可以想到它~~下面先来对它的使用有一个基本的了解,只有对于基础有了掌握对于高大上的效果你才能有比较好的掌控,先来了解四个参数的含义:

  • gravity
    它表示扣图的方向,是从左还是从右,啥意思?拿我们要作案的对象来说:

  • w、h
    它代表目标矩形的宽高,也就是最终要生成的图的宽高,很明显咱们最终扣出来的图就是原图的高度,用灰图或亮图任意一个高宽都可以:
  • container
    它是指被扣的Rect矩形区域,对于咱们来说就是getBounds()返回的矩形区域就成了:

    所以我们可以直接拿来用:

  • outRect
    这个就比较好理解了,最终生成的目标矩形区域,该矩形其实也就是最终要用画面来clipRect()的:

好,下面咱们拿一个图片来做一个试验,从图中扣出我们想要矩形的位置出来,这里以灰色的这张图作为试验品,代码如下:

运行看一下:

 

很明显就是这块位置:

好,我们最终的目标是想从它里面将左半边部分扣出来,其实也就是改变一下高度既可,当然此时宽高就得计算得到:宽度为整个图片的一半,高度则为整个图片的高度,具体修改如下:

运行:

逻辑实现:

好,知道了怎么来扣半图了,接下来则再来将亮图的右半部分扣出来,其我们要的一阴一阳的效果就可以达成了,这个实现就比较简单了,下面看代码:

package com.paintgradient.test.canvas;import android.annotation.SuppressLint;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.Gravity;public class RevealDrawable extends Drawable {private Drawable mUnselectedDrawable;private Drawable mSelectedDrawable;public RevealDrawable(Drawable unselected, Drawable selected) {mUnselectedDrawable = unselected;mSelectedDrawable = selected;}@Overridepublic void draw(Canvas canvas) {Rect containerRect = getBounds();Rect outRect = new Rect();//从一个已有的bound矩形边界范围当中抠出一个我们想要的矩形Gravity.apply(//从左边扣还是从右边扣Gravity.LEFT,//目标矩形宽containerRect.width() / 2,//目标矩形高containerRect.height(),//被扣的地方containerRect,//抠出来outRect);canvas.save();canvas.clipRect(outRect);mUnselectedDrawable.draw(canvas);canvas.restore();Gravity.apply(//从左边扣还是从右边扣Gravity.RIGHT,//目标矩形宽containerRect.width() / 2,//目标矩形高containerRect.height(),//被扣的地方containerRect,outRect);canvas.clipRect(outRect);mSelectedDrawable.draw(canvas);}@Overrideprotected void onBoundsChange(Rect bounds) {// 定好两个Drawable图片的宽高---边界boundsmUnselectedDrawable.setBounds(bounds);mSelectedDrawable.setBounds(bounds);Log.d("cexo", "w = " + bounds.width());}@Overridepublic int getIntrinsicWidth() {//得到Drawable的实际宽度return Math.max(mSelectedDrawable.getIntrinsicWidth(),mUnselectedDrawable.getIntrinsicWidth());}@Overridepublic int getIntrinsicHeight() {//得到Drawable的实际高度return Math.max(mSelectedDrawable.getIntrinsicHeight(),mUnselectedDrawable.getIntrinsicHeight());}@Overridepublic void setAlpha(int alpha) {}@Overridepublic void setColorFilter(ColorFilter cf) {}@SuppressLint("WrongConstant")@Overridepublic int getOpacity() {return 0;}}

其中要特别的注意:

最终就成功实现了一阴一阳的扣图效果了,等于是用二张图来实现的,当然其实也可以用一张图,然后通过滤镜的功能达成一阴一阳,这块可以自行拓展,重点是学会这种实现的思路。

GallaryHorizonalScrollView滑动效果实现:

知道了如何扣图了之后,接下来则就需要依赖这个基本知识实现最终开篇所示的那个滑动效果了。

将所有View添加到HorizontalScrollView中:

这里先将所有用到的资源图都导进来,都是成对的图片,如下:

avft、avft_active:

box_stack、box_stack_active:

bubble_frame、bubble_frame_active:

bubbles、bubbles_active:

bullseye、bullseye_active:

circle_filled、circle_filled_active:

circle_outline、circle_outline_active:

然后声明一下滑动控件:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".MainActivity"><com.paintgradient.test.canvas.GallaryHorizonalScrollViewandroid:id="@+id/hsv"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_gravity="center_vertical"android:background="#AA444444"android:scrollbars="none" />
</LinearLayout>
package com.paintgradient.test;import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ImageView;import com.paintgradient.test.canvas.GallaryHorizonalScrollView;
import com.paintgradient.test.canvas.RevealDrawable;public class MainActivity extends AppCompatActivity {private ImageView iv;private int[] imgIds = new int[]{ //7个R.drawable.avft,R.drawable.box_stack,R.drawable.bubble_frame,R.drawable.bubbles,R.drawable.bullseye,R.drawable.circle_filled,R.drawable.circle_outline,R.drawable.avft,R.drawable.box_stack,R.drawable.bubble_frame,R.drawable.bubbles,R.drawable.bullseye,R.drawable.circle_filled,R.drawable.circle_outline};private int[] imgIds_active = new int[]{R.drawable.avft_active, R.drawable.box_stack_active, R.drawable.bubble_frame_active,R.drawable.bubbles_active, R.drawable.bullseye_active, R.drawable.circle_filled_active,R.drawable.circle_outline_active,R.drawable.avft_active, R.drawable.box_stack_active, R.drawable.bubble_frame_active,R.drawable.bubbles_active, R.drawable.bullseye_active, R.drawable.circle_filled_active,R.drawable.circle_outline_active};public Drawable[] revealDrawables;private GallaryHorizonalScrollView hzv;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initData();initView();}private void initData() {revealDrawables = new Drawable[imgIds.length];}private void initView() {for (int i = 0; i < imgIds.length; i++) {RevealDrawable rd = new RevealDrawable(getResources().getDrawable(imgIds[i]),getResources().getDrawable(imgIds_active[i]));revealDrawables[i] = rd;}hzv = findViewById(R.id.hsv);hzv.addImageViews(revealDrawables);}
}
package com.paintgradient.test.canvas;import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.LinearLayout;public class GallaryHorizonalScrollView extends HorizontalScrollView {private static final String TAG = "cexo";private LinearLayout container;public GallaryHorizonalScrollView(Context context, AttributeSet attrs) {super(context, attrs);init();}public GallaryHorizonalScrollView(Context context) {super(context);init();}private void init() {//在ScrollView里面放置一个水平线性布局,里面再放置ImageViewLinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.WRAP_CONTENT);container = new LinearLayout(getContext());container.setLayoutParams(params);}//添加图片的方法public void addImageViews(Drawable[] revealDrawables) {for (int i = 0; i < revealDrawables.length; i++) {ImageView img = new ImageView(getContext());img.setImageDrawable(revealDrawables[i]);container.addView(img);}addView(container);}}

此时运行:

可以看到每个ImageView显示的图片都是一阴一阳的,因为目前我们的自定义Drawable的逻辑是写死成这样了:

这里跟原效果还是有一个区别就是进来之后,第一个图片的位置跟左边是有间距的,以及最后一个图片也是有间距的,回忆一下预其的效果:

 

那为啥要设置左右的间距呢?其实也很好理解,因为如果不设置间距,像第一个和最后一个图像是不是没有办法滑到中间呀,预期的效果是滑到中间的则为选中高亮,再来看一下咱们目前的效果:

 

而同样的,对于最后的区域:

所以咱们先来解决这个小细节,其实很好解决,因为整个滑动里面的ImageView都是添加到container父布局中的:

所以我们给这个container的头和尾加个padding不就可以解决了,那加到哪呢?这里加到onLayout就可以了,代码比较简单就直接贴出来了:

所以此时就变成这样了:

ImageView.setImageLevel()理解:

好,接下来则要到烧脑的时间了,那怎么能最终达到我们跟随手机可以滑动其整个的阴暗效果呢?这里需要有一定的技巧的,而且前提需要先理解一个平常不怎么使用的API,也就是如标题所示: 

这官方注解等于没说,完全不理解这方法的含义,先不管啥含义了,先看一下它里面的实现,最终会看到一个新大陆:

而mDrawable就是我们调用这个方法赋值的:

好,接着再跟进去:

而对于我们自定义Drawable来说就可以重写它了:

当然最终要实现我们想要的效果肯定是要用到这个方法的,但是!!现在对于这个方法有啥用还是一脸茫然,此时先读一读官方说明:

读完之后,貌似可以看到可以通过控制这个level的值来达到图片的不断刷新,也就是类似于自定View调用invalidate的效果,不过还是有些抽象,这里由于我们肯定是需要我们的Drawable要不断进行变化,所以先按官方要求重写onLevelChange()方法:

那咱们主动来调用一下setLevel试一下效果:

 

运行:

很明显我们在滑动时是要不断对咱们的Drawable进行图像扣图操作的,此时就可以利用这个特性,通过不断调用setImageLevel()来达到不断更新的目的。

滑动监听来找到渐变左右图的位置:

由于我们需要根据滑动监听来确定当前滑动的图片和那一张图片的位置才能够对其进行相印的扣图逻辑,所以先来处理监听,比如简单:

运行看一下:

而这里先将else中的灰度部分先处理了,这个比较简单,直接将ImageLevel定为0既可:

而在RevealDrawable中的onDraw()中这样写:

@Overridepublic void draw(Canvas canvas) {int level = getLevel();if (level == 0) {mUnselectedDrawable.draw(canvas);} else {Rect containerRect = getBounds();Rect outRect = new Rect();//从一个已有的bound矩形边界范围当中抠出一个我们想要的矩形Gravity.apply(//从左边扣还是从右边扣Gravity.LEFT,//目标矩形宽containerRect.width() / 2,//目标矩形高containerRect.height(),//被扣的地方containerRect,//抠出来outRect);canvas.save();canvas.clipRect(outRect);mUnselectedDrawable.draw(canvas);canvas.restore();Gravity.apply(//从左边扣还是从右边扣Gravity.RIGHT,//目标矩形宽containerRect.width() / 2,//目标矩形高containerRect.height(),//被扣的地方containerRect,outRect);canvas.clipRect(outRect);mSelectedDrawable.draw(canvas);}}

运行:

 

可以看到随着滑动,其没有在相隔的图像之外的会动态都切换成灰色图像了:

计算左右图的Level:

重中之重的问题来了,如何动态根据滑动来处理左右图位置的高亮效果,这个是个很头疼的问题。。 这里就需要一定的技巧了,我们知道ImageLevel的范围值官方也说了,是从0~10000:

所以这里需要用一个假设法,假设这中间的三个图像就是占10000等份:

为啥要定义三个图像呢?因为你根据预期的效果可以发现,其实就是中间三个图在不断的进行变化,而这三个图之外的基本上就是全灰不用做渐变处理的。另外每个图片占5000等份,所以咱们就可以标出三个值来:

可以看到,如果Level是0和10000时,很显然直接变灰就可以了,而如果是5000则直接变彩,所以咱们先把这个逻辑写进来:

接下来则需要根据滑动来动态计算不同图像的Level值了,这里又有点烧脑了,这里先来图解一下思路:

此时重点就是如何计算m了,也就是滑动所占的Level的等份,这个比较简单,一个图片是占5000等份Level,假设图片宽度为w,那图片每像素所占的比率则为5000/w=r,然后我们再用这个r剩以滑出去的距离数就可以求出来,整个计算公式也就搞定了,所以对于左右图片的Level值也就可以确定了,如下:

此时运行看一下:

其中可以看到最终有一个状态就如我们所期望的中间整个变亮了,因为有张图刚好是滑在了5000的位置了:

 

RevealDrawable根据level值进行最终处理:

好,最后就是来处理混合效果了,也就是扣图这块,这里就涉及到是从左扣还是从右扣了,先来用示意图给整清楚思路:

上面这图的思路一定得要理解,不然看代码会比较晕,下面则具体看一下代码,理解了这个方向之后其实也就不难了,代码如下:

package com.paintgradient.test.canvas;import android.annotation.SuppressLint;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.Gravity;public class RevealDrawable extends Drawable {private Drawable mUnselectedDrawable;private Drawable mSelectedDrawable;public RevealDrawable(Drawable unselected, Drawable selected) {mUnselectedDrawable = unselected;mSelectedDrawable = selected;}@Overridepublic void draw(Canvas canvas) {int level = getLevel();if (level == 10000 || level == 0) {//设置灰色mUnselectedDrawable.draw(canvas);} else if (level == 5000) {//设置成彩色mSelectedDrawable.draw(canvas);} else {//这种则为混色Rect containerRect = getBounds();Rect outRect = new Rect();//1.先绘制灰色部分float ratio = (level / 5000f) - 1f;int gravity = ratio < 0 ? Gravity.LEFT : Gravity.RIGHT;//从一个已有的bound矩形边界范围当中抠出一个我们想要的矩形Gravity.apply(//从左边扣还是从右边扣gravity,//目标矩形宽(int) (containerRect.width() * Math.abs(ratio)),//目标矩形高containerRect.height(),//被扣的地方containerRect,//抠出来outRect);canvas.save();canvas.clipRect(outRect);mUnselectedDrawable.draw(canvas);canvas.restore();gravity = ratio < 0 ? Gravity.RIGHT : Gravity.LEFT;//这里的方向跟上面的图刚好相反Gravity.apply(//从左边扣还是从右边扣gravity,//目标矩形宽containerRect.width() - (int) (containerRect.width() * Math.abs(ratio)),//这里需要相减一下//目标矩形高containerRect.height(),//被扣的地方containerRect,outRect);canvas.save();//保存画布canvas.clipRect(outRect);mSelectedDrawable.draw(canvas);canvas.restore();//恢复之前保存的画布}}@Overrideprotected void onBoundsChange(Rect bounds) {// 定好两个Drawable图片的宽高---边界boundsmUnselectedDrawable.setBounds(bounds);mSelectedDrawable.setBounds(bounds);}@Overridepublic int getIntrinsicWidth() {//得到Drawable的实际宽度return Math.max(mSelectedDrawable.getIntrinsicWidth(),mUnselectedDrawable.getIntrinsicWidth());}@Overridepublic int getIntrinsicHeight() {//得到Drawable的实际高度return Math.max(mSelectedDrawable.getIntrinsicHeight(),mUnselectedDrawable.getIntrinsicHeight());}@Overrideprotected boolean onLevelChange(int level) {Log.e("cexo", "RevealDrawable.onLevelChange():" + level);// 当设置level的时候回调---提醒自己重新绘制invalidateSelf();return true;}@Overridepublic void setAlpha(int alpha) {}@Overridepublic void setColorFilter(ColorFilter cf) {}@SuppressLint("WrongConstant")@Overridepublic int getOpacity() {return 0;}}

最后在初始化时应该给第一个ImageView设置一下Level:

至此,终于搞定,真是挺麻烦了~~通过这个案例对于如何扣图以及ImageLevel的使用就比较熟悉了。

这篇关于android高级UI之Canvas综合案例操练的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/306870

相关文章

Golang操作DuckDB实战案例分享

《Golang操作DuckDB实战案例分享》DuckDB是一个嵌入式SQL数据库引擎,它与众所周知的SQLite非常相似,但它是为olap风格的工作负载设计的,DuckDB支持各种数据类型和SQL特性... 目录DuckDB的主要优点环境准备初始化表和数据查询单行或多行错误处理和事务完整代码最后总结Duck

Python中的可视化设计与UI界面实现

《Python中的可视化设计与UI界面实现》本文介绍了如何使用Python创建用户界面(UI),包括使用Tkinter、PyQt、Kivy等库进行基本窗口、动态图表和动画效果的实现,通过示例代码,展示... 目录从像素到界面:python带你玩转UI设计示例:使用Tkinter创建一个简单的窗口绘图魔法:用

MySQL不使用子查询的原因及优化案例

《MySQL不使用子查询的原因及优化案例》对于mysql,不推荐使用子查询,效率太差,执行子查询时,MYSQL需要创建临时表,查询完毕后再删除这些临时表,所以,子查询的速度会受到一定的影响,本文给大家... 目录不推荐使用子查询和JOIN的原因解决方案优化案例案例1:查询所有有库存的商品信息案例2:使用EX

element-ui下拉输入框+resetFields无法回显的问题解决

《element-ui下拉输入框+resetFields无法回显的问题解决》本文主要介绍了在使用ElementUI的下拉输入框时,点击重置按钮后输入框无法回显数据的问题,具有一定的参考价值,感兴趣的... 目录描述原因问题重现解决方案方法一方法二总结描述第一次进入页面,不做任何操作,点击重置按钮,再进行下

Android数据库Room的实际使用过程总结

《Android数据库Room的实际使用过程总结》这篇文章主要给大家介绍了关于Android数据库Room的实际使用过程,详细介绍了如何创建实体类、数据访问对象(DAO)和数据库抽象类,需要的朋友可以... 目录前言一、Room的基本使用1.项目配置2.创建实体类(Entity)3.创建数据访问对象(DAO

Python中列表的高级索引技巧分享

《Python中列表的高级索引技巧分享》列表是Python中最常用的数据结构之一,它允许你存储多个元素,并且可以通过索引来访问这些元素,本文将带你深入了解Python列表的高级索引技巧,希望对... 目录1.基本索引2.切片3.负数索引切片4.步长5.多维列表6.列表解析7.切片赋值8.删除元素9.反转列表

正则表达式高级应用与性能优化记录

《正则表达式高级应用与性能优化记录》本文介绍了正则表达式的高级应用和性能优化技巧,包括文本拆分、合并、XML/HTML解析、数据分析、以及性能优化方法,通过这些技巧,可以更高效地利用正则表达式进行复杂... 目录第6章:正则表达式的高级应用6.1 模式匹配与文本处理6.1.1 文本拆分6.1.2 文本合并6

Android WebView的加载超时处理方案

《AndroidWebView的加载超时处理方案》在Android开发中,WebView是一个常用的组件,用于在应用中嵌入网页,然而,当网络状况不佳或页面加载过慢时,用户可能会遇到加载超时的问题,本... 目录引言一、WebView加载超时的原因二、加载超时处理方案1. 使用Handler和Timer进行超

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD