Android App开发之自定义图形中位图与图形互转、剪裁图形内部区域、给图形添加部件的讲解及实战(附源码 简单易懂)

简介: Android App开发之自定义图形中位图与图形互转、剪裁图形内部区域、给图形添加部件的讲解及实战(附源码 简单易懂)

需要图片和源码点赞关注收藏后评论区留言~~~

一、位图与图形互转

Drawable用于在界面上展示图片,Bitmap用于加工图像数据,所以两者之间的转换非常有必要,位图图形BitmapDrawable正是二者之间的桥梁,图形对象与位图对象互相转换都需要它。

图形对象转换成位图对象有个前提,就是该图形原本便是位图格式,否则会转换失败

Drawable类有个setAlpha方法,可以设置图形的灰度值,下面是位图转换成图形对象后再调用setAlpha方法  效果如下

可见不同的灰度比例会有不同的效果

代码如下

Java类

package com.example.picture;
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.Spinner;
public class DrawableConvertActivity extends AppCompatActivity {
    private Bitmap mOriginBitmap; // 原始位图
    private ImageView iv_picture; // 声明一个图像视图对象
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_drawable_convert);
        iv_picture = findViewById(R.id.iv_picture);
        mOriginBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.mandarin_duck);
        initAlphaSpinner(); // 初始化灰度比例下拉框
    }
    // 初始化灰度比例下拉框
    private void initAlphaSpinner() {
        ArrayAdapter<String> alphaAdapter = new ArrayAdapter<>(this,
                R.layout.item_select, alphaNameArray);
        Spinner sp_alpha = findViewById(R.id.sp_alpha);
        sp_alpha.setPrompt("请选择灰度比例");
        sp_alpha.setAdapter(alphaAdapter);
        sp_alpha.setOnItemSelectedListener(new AlphaSelectedListener());
        sp_alpha.setSelection(0);
    }
    private String[] alphaNameArray = {"1", "0.75", "0.5", "0.25", "0"};
    class AlphaSelectedListener implements AdapterView.OnItemSelectedListener {
        public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
            double ratio = Double.parseDouble(alphaNameArray[arg2]);
            // 根据指定位图创建图形对象
            Drawable drawable = new BitmapDrawable(getResources(), mOriginBitmap);
            drawable.setAlpha((int) (255*ratio)); // 设置图形的灰度值
            iv_picture.setImageDrawable(drawable); // 设置图像视图的图形对象
        }
        public void onNothingSelected(AdapterView<?> arg0) {}
    }
}

XML文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="40dp">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:paddingLeft="5dp"
            android:gravity="center"
            android:text="请选择灰度比例"
            android:textColor="@color/black"
            android:textSize="17sp" />
        <Spinner
            android:id="@+id/sp_alpha"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center"
            android:spinnerMode="dialog" />
    </LinearLayout>
    <ImageView
        android:id="@+id/iv_picture"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:scaleType="centerInside" />
</LinearLayout>

二、剪裁图形内部区域

有时候为了美观,并不会显示整个图像,而是显示剪裁后的图像,比如QQ的圆形头像等等。圆形剪裁正是位图图形的拿手好戏,只要调用画笔工具的setShader方法,设置位图着色器即可

下面实现 椭圆 圆角矩形 圆形的剪裁效果

代码如下

Java类

package com.example.picture;
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.Spinner;
import com.example.picture.widget.CircleDrawable;
import com.example.picture.widget.OvalDrawable;
import com.example.picture.widget.RoundDrawable;
public class DrawableCutActivity extends AppCompatActivity {
    private Bitmap mOriginBitmap; // 原始位图
    private ImageView iv_picture; // 声明一个图像视图对象
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_drawable_cut);
        iv_picture = findViewById(R.id.iv_picture);
        mOriginBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.mandarin_duck);
        initMethodSpinner(); // 初始化剪裁方式下拉框
    }
    // 初始化剪裁方式下拉框
    private void initMethodSpinner() {
        ArrayAdapter<String> methodAdapter = new ArrayAdapter<>(this,
                R.layout.item_select, methodArray);
        Spinner sp_method = findViewById(R.id.sp_method);
        sp_method.setPrompt("请选择剪裁方式");
        sp_method.setAdapter(methodAdapter);
        sp_method.setOnItemSelectedListener(new MethodSelectedListener());
        sp_method.setSelection(0);
    }
    private String[] methodArray = {"不裁剪", "圆形剪裁", "椭圆剪裁", "圆角矩形剪裁"};
    class MethodSelectedListener implements AdapterView.OnItemSelectedListener {
        public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
            if (arg2 == 0) { // 不裁剪
                iv_picture.setImageBitmap(mOriginBitmap); // 设置图像视图的位图对象
            } else if (arg2 == 1) { // 圆形剪裁
                Drawable drawable = new CircleDrawable(DrawableCutActivity.this, mOriginBitmap);
                iv_picture.setImageDrawable(drawable); // 设置图像视图的图形对象
            } else if (arg2 == 2) { // 椭圆剪裁
                Drawable drawable = new OvalDrawable(DrawableCutActivity.this, mOriginBitmap);
                iv_picture.setImageDrawable(drawable); // 设置图像视图的图形对象
            } else if (arg2 == 3) { // 圆角矩形剪裁
                Drawable drawable = new RoundDrawable(DrawableCutActivity.this, mOriginBitmap);
                iv_picture.setImageDrawable(drawable); // 设置图像视图的图形对象
            }
        }
        public void onNothingSelected(AdapterView<?> arg0) {}
    }
}

XML文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="40dp">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:paddingLeft="5dp"
            android:gravity="center"
            android:text="请选择剪裁方式"
            android:textColor="@color/black"
            android:textSize="17sp" />
        <Spinner
            android:id="@+id/sp_method"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center"
            android:spinnerMode="dialog" />
    </LinearLayout>
    <ImageView
        android:id="@+id/iv_picture"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:scaleType="centerInside" />
</LinearLayout>

三、给图形添加小部件

除了剪裁图形之外,还能给图形添加小部件,比如文字,图标等等,原来自定义图形类的时候,重写draw方法等同于重写视图的onDraw方法,因此在draw方法中就可以添加图案。

此处可以设置个性化字体,用到了字体工具Typeface的createFromAsset方法,该方法允许从assets目录下的字体文件生成字体对象,然后调用画笔对象的setTypeface方法,就能使文字呈现对应的字体样式

同样能给图片加水印 效果如下

代码如下

Java类

package com.example.picture;
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Typeface;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.Spinner;
import com.example.picture.widget.MarkTextDrawable;
public class DrawableTextActivity extends AppCompatActivity {
    private final static String TAG = "DrawableTextActivity";
    private Bitmap mOriginBitmap; // 原始位图
    private ImageView iv_picture; // 声明一个图像视图对象
    private Typeface[] mTypeFaceArray; // 字体数组
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_drawable_text);
        iv_picture = findViewById(R.id.iv_picture);
        mOriginBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.mandarin_duck);
        iv_picture.setImageBitmap(mOriginBitmap); // 设置图像视图的位图对象
        new Handler(Looper.myLooper()).post(() -> loadTypeFace()); // 加载字体文件
    }
    // 加载字体文件
    private void loadTypeFace() {
        mTypeFaceArray = new Typeface[fontFileArray.length];
        for (int i=0; i<fontFileArray.length; i++) {
            String fontFile = "fonts/" + fontFileArray[i] + ".ttf";
            // 根据assets目录下的字体文件创建字体对象
            mTypeFaceArray[i] = Typeface.createFromAsset(getAssets(), fontFile);
        }
        initFontSpinner(); // 初始化中文字体下拉框
    }
    // 初始化中文字体下拉框
    private void initFontSpinner() {
        ArrayAdapter<String> fontAdapter = new ArrayAdapter<>(this,
                R.layout.item_select, fontNameArray);
        Spinner sp_font = findViewById(R.id.sp_font);
        sp_font.setPrompt("请选择中文字体");
        sp_font.setAdapter(fontAdapter);
        sp_font.setOnItemSelectedListener(new FontSelectedListener());
        sp_font.setSelection(0);
    }
    private String[] fontNameArray = {"常规", "仿宋", "楷体", "隶书", "黑体", "幼圆",
            "华文行楷", "华文新魏", "华文彩云", "华文琥珀", "方正舒体", "方正姚体"};
    private String[] fontFileArray = {"Regular", "FangSong", "KaiTi", "LiShu", "HeiTi", "YouYuan",
            "HangKai", "XinWei", "CaiYun", "HuPo", "ShuTi", "YaoTi"};
    class FontSelectedListener implements AdapterView.OnItemSelectedListener {
        public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
            // 根据指定位图创建水印图形对象
            MarkTextDrawable drawable = new MarkTextDrawable(DrawableTextActivity.this, mOriginBitmap);
            drawable.setMarkerText("鸳鸯戏水", mTypeFaceArray[arg2]); // 设置水印文字及其字体
            iv_picture.setImageDrawable(drawable); // 设置图像视图的图形对象
        }
        public void onNothingSelected(AdapterView<?> arg0) {}
    }
}

XML文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="40dp">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:paddingLeft="5dp"
            android:gravity="center"
            android:text="请选择中文字体"
            android:textColor="@color/black"
            android:textSize="17sp" />
        <Spinner
            android:id="@+id/sp_font"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center"
            android:spinnerMode="dialog" />
    </LinearLayout>
    <ImageView
        android:id="@+id/iv_picture"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:scaleType="centerInside" />
</LinearLayout>

创作不易 觉得有帮助请 点赞关注收藏~~~

相关文章
|
Android开发 UED 计算机视觉
Android自定义view之线条等待动画(灵感来源:金铲铲之战)
本文介绍了一款受游戏“金铲铲之战”启发的Android自定义View——线条等待动画的实现过程。通过将布局分为10份,利用`onSizeChanged`测量最小长度,并借助画笔绘制动态线条,实现渐变伸缩效果。动画逻辑通过四个变量控制线条的增长与回退,最终形成流畅的等待动画。代码中详细展示了画笔初始化、线条绘制及动画更新的核心步骤,并提供完整源码供参考。此动画适用于加载场景,提升用户体验。
706 5
Android自定义view之线条等待动画(灵感来源:金铲铲之战)
|
Android开发
Android自定义view之利用PathEffect实现动态效果
本文介绍如何在Android自定义View中利用`PathEffect`实现动态效果。通过改变偏移量,结合`PathEffect`的子类(如`CornerPathEffect`、`DashPathEffect`、`PathDashPathEffect`等)实现路径绘制的动态变化。文章详细解析了各子类的功能与参数,并通过案例代码展示了如何使用`ComposePathEffect`组合效果,以及通过修改偏移量实现动画。最终效果为一个菱形图案沿路径运动,源码附于文末供参考。
237 0
|
XML Java Android开发
Android自定义view之网易云推荐歌单界面
本文详细介绍了如何通过自定义View实现网易云音乐推荐歌单界面的效果。首先,作者自定义了一个圆角图片控件`MellowImageView`,用于绘制圆角矩形图片。接着,通过将布局放入`HorizontalScrollView`中,实现了左右滑动功能,并使用`ViewFlipper`添加图片切换动画效果。文章提供了完整的代码示例,包括XML布局、动画文件和Java代码,最终展示了实现效果。此教程适合想了解自定义View和动画效果的开发者。
509 65
Android自定义view之网易云推荐歌单界面
|
XML 前端开发 Android开发
一篇文章带你走近Android自定义view
这是一篇关于Android自定义View的全面教程,涵盖从基础到进阶的知识点。文章首先讲解了自定义View的必要性及简单实现(如通过三个构造函数解决焦点问题),接着深入探讨Canvas绘图、自定义属性设置、动画实现等内容。还提供了具体案例,如跑马灯、折线图、太极图等。此外,文章详细解析了View绘制流程(measure、layout、draw)和事件分发机制。最后延伸至SurfaceView、GLSurfaceView、SVG动画等高级主题,并附带GitHub案例供实践。适合希望深入理解Android自定义View的开发者学习参考。
914 84
|
8月前
|
人工智能 小程序 搜索推荐
【一步步开发AI运动APP】十二、自定义扩展新运动项目2
本文介绍如何基于uni-app运动识别插件实现“双手并举”自定义扩展运动,涵盖动作拆解、姿态检测规则构建及运动分析器代码实现,助力开发者打造个性化AI运动APP。
|
11月前
|
存储 Android开发 数据安全/隐私保护
Thanox安卓系统增加工具下载,管理、阻止、限制后台每个APP运行情况
Thanox是一款Android系统管理工具,专注于权限、后台启动及运行管理。支持应用冻结、系统优化、UI自定义和模块管理,基于Xposed框架开发,安全可靠且开源免费,兼容Android 6.0及以上版本。
1311 4
|
前端开发 Android开发 UED
讲讲Android为自定义view提供的SurfaceView
本文详细介绍了Android中自定义View时使用SurfaceView的必要性和实现方式。首先分析了在复杂绘制逻辑和高频界面更新场景下,传统View可能引发卡顿的问题,进而引出SurfaceView作为解决方案。文章通过Android官方Demo展示了SurfaceView的基本用法,包括实现`SurfaceHolder.Callback2`接口、与Activity生命周期绑定、子线程中使用`lockCanvas()`和`unlockCanvasAndPost()`方法完成绘图操作。
333 3
|
Android开发 开发者
Android自定义view之围棋动画(化繁为简)
本文介绍了Android自定义View的动画实现,通过两个案例拓展动态效果。第一个案例基于`drawArc`方法实现单次动画,借助布尔值控制动画流程。第二个案例以围棋动画为例,从简单的小球直线运动到双向变速运动,最终实现循环动画效果。代码结构清晰,逻辑简明,展示了如何化繁为简实现复杂动画,帮助读者拓展动态效果设计思路。文末提供完整源码,适合初学者和进阶开发者学习参考。
228 0
Android自定义view之围棋动画(化繁为简)
|
12月前
《仿盒马》app开发技术分享-- 自定义标题栏&商品详情初探(9)
上一节我们实现了顶部toolbar的地址选择,会员码展示,首页的静态页面就先告一段落,这节我们来实现商品列表item的点击传值、自定义标题栏。
138 0

热门文章

最新文章