Android炫酷应用300例读书笔记四

第4章图形和图像
89.在自定义View中绘制径向渐变的图形

public class MainActivity extends AppCompatActivity{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        setContentView(new MyView(this));
        super.onCreate(savedInstanceState);
    }


    class MyView extends View{
        private Paint mPaint;
        public MyView(Context context) {
            super(context);
            mPaint = new Paint();
            mPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
            mPaint.setAntiAlias(true);
        }
        @Override
        protected void onDraw(Canvas canvas){
            super.onDraw(canvas);
            DisplayMetrics dm = new DisplayMetrics();
            getWindowManager().getDefaultDisplay().getMetrics(dm);
            int width = dm.widthPixels;
            int height = dm.heightPixels;
            RadialGradient radialGradient = new RadialGradient(width/2,height/2 - 160,width/2 - 20,new int[]{
                    Color.YELLOW,Color.GREEN,Color.TRANSPARENT,Color.RED
            },null, Shader.TileMode.REPEAT);
            mPaint.setShader(radialGradient);
            canvas.drawCircle(width/2,height/2 - 160,width/2 - 20,mPaint);
        }

    }

}

90.在自定义View中实现图像波纹起伏效果

public class MainActivity extends AppCompatActivity{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    
}

WaveView

public class WaveView extends View {
    private int mWidth = 40;//横向划分的方格数目
    private int mHeight = 40;//纵向划分的方格数目
    private float FREQUENCY = 0.1f;//三角函数的频率大小
    private int AMPLITUDE = 80;//三角函数的振幅大小
    private int mCount = (mWidth + 1) * (mHeight +1);
    private Bitmap mBitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.image1);
    //保存每个小方格的交差点坐标
    private float[] mPoints = new float[mCount * 2];
    private float[] mVerts = new float[mCount * 2];
    private float k;

    public WaveView(Context context, @Nullable AttributeSet attrs) {
        this(context,attrs,0);
    }

    public WaveView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initData();
    }

    @Override
    protected void onDraw(Canvas canvas){
        flagWave();
        k += FREQUENCY;
        canvas.translate(0,150);//纵向平移画布
        canvas.drawBitmapMesh(mBitmap,mWidth,mHeight,mVerts,0,null,0,null);
        invalidate();
    }

    private void initData(){
        float width = mBitmap.getWidth();
        float height = mBitmap.getHeight();
        int index = 0;
        //通过遍历所有小方格,得到原图每个交叉点坐标,并把它们保存在数组中
        for (int i = 0;i <= mHeight;i++){
            float fy = height * i / mHeight;
            for (int j = 0;j <= mWidth;j++){
                float fx = height * j / mWidth;
                mPoints[index * 2 + 0] = mVerts[index * 2 + 0] = fx;
                mPoints[index * 2 + 1] = mVerts[index * 2 + 1] = fy + AMPLITUDE * 1.2f;
                index++;
            }
        }
    }
    //加入正弦函数算法,修改交差点坐标得到波纹效果,这里只修改了y坐标,x坐标不变
    public void flagWave(){
        for (int i = 0;i < mHeight;i++){
            for (int j = 0;j < mWidth;j++){
                mVerts[(i * (mWidth + 1) + j) * 2 + 0] += 0;
                float offSetY = (float) Math.sin((float) j / mWidth * 2 * Math.PI + Math.PI * k);
                mVerts[(i * (mWidth + 1) + j) * 2 + 1] = mPoints[(i * (mWidth + 1) + j) * 2 + 1] +
                        offSetY * AMPLITUDE;
            }
        }
    }
}
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

   <com.cc.uisample.WaveView
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"/>
</android.support.constraint.ConstraintLayout>

扩展延伸:
Android自定义View系列之正弦曲线
https://www.jianshu.com/p/e38c76de0631
android 自定义view-水波纹进度球
https://www.jianshu.com/p/9d5bb3e17d5c

91.在自定义View中使用椭圆裁剪图像

public class MainActivity extends AppCompatActivity{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        setContentView(new MyView(this));
        super.onCreate(savedInstanceState);
    }


    class MyView extends View{
        private Paint mPaint;
        public MyView(Context context) {
            super(context);
            mPaint = new Paint();

        }
        @Override
        protected void onDraw(Canvas canvas){
            super.onDraw(canvas);
            DisplayMetrics dm = new DisplayMetrics();
            getWindowManager().getDefaultDisplay().getMetrics(dm);
            int width = dm.widthPixels;
            int height = dm.heightPixels;
            Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.image1);
            canvas.drawOval(10,height / 5,width - 10, height * 3 / 5,mPaint);
            mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD));
            canvas.drawBitmap(bitmap,0,0,mPaint);
        }

    }

}

参考链接:
实现圆形、圆角,椭圆等自定义图片View
https://www.jianshu.com/p/092b4e0865f5

92.通过PorterDuff模式增暗显示两幅图像
这个代码设置的效果的显示跟图片的选取有关,这里我用的是前面的章节用到的image1和image2,这两个是暗色系的图片。

public class MainActivity extends AppCompatActivity{
    private Button mButton1;
    private Button mButton2;
    private ImageView mImageView;
    private Bitmap mBitmap1;
    private Bitmap mBitmap2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mButton1 = (Button) findViewById(R.id.button1);
        mButton1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Bitmap bitmapCopy = mBitmap2.copy(Bitmap.Config.ARGB_8888,true);
                Canvas canvas = new Canvas(bitmapCopy);
                Paint paint = new Paint();
                //获取两幅图每个位置上最暗的像素并显示
                paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DARKEN));
                canvas.drawBitmap(mBitmap1,0,0,paint);
                mImageView.setImageBitmap(bitmapCopy);
            }
        });
        mButton2 = (Button) findViewById(R.id.button2);
        mButton2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mImageView.setImageBitmap(mBitmap1);
            }
        });
        mImageView = (ImageView) findViewById(R.id.imageView);
        mBitmap1 = BitmapFactory.decodeResource(getResources(),R.mipmap.image1);
        mBitmap2 = BitmapFactory.decodeResource(getResources(),R.mipmap.image2);

    }


}
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">


    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="特效图像"
        android:layout_marginLeft="60dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="30dp"/>

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="原始图像"
        android:layout_marginRight="60dp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="30dp"/>

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="288dp"
        android:layout_height="247dp"
        app:srcCompat="@mipmap/image1"
        android:layout_marginLeft="8dp"
        app:layout_constraintLeft_toLeftOf="parent"
        android:layout_marginRight="8dp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="114dp"/>
</android.support.constraint.ConstraintLayout>

参考链接:
Android 自定义View学习(五)——Paint 关于PorterDuffXfermode学习
https://www.jianshu.com/p/0f64daf202f2
93.通过PorterDuff模式将图像裁剪成五角星
本小节由于书中给出的五角星画法代码因为代码不全的原因实际运行有点问题,所以我改掉了这部分的代码。

public class MainActivity extends AppCompatActivity{
    private ImageView mImageView;
    private Bitmap mBitmap1;
    private int mWidth = 1080;
    private int mHeight =1920;
    private float xA = 540;
    private float yA = 200;
    private int r = 1000; //五角星边长

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mImageView = (ImageView) findViewById(R.id.imageView);
        mBitmap1 = BitmapFactory.decodeResource(getResources(),R.drawable.test);
        mImageView.setImageBitmap(getNewImage(mBitmap1));

    }



    public Bitmap getNewImage(Bitmap bitmap){
        Bitmap bitmapSrc = Bitmap.createBitmap(mWidth,mHeight, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmapSrc);
        Paint paint = new Paint();
        Path path = new Path();
        float[] floats = fivePoints(xA, yA,r);
        for (int i = 0; i < floats.length - 1; i++) {
            path.lineTo(floats[i], floats[i += 1]);
        }

        path.close();
        canvas.translate(0,360);
        canvas.drawPath(path,paint);//绘制五角星
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        Rect rect = new Rect(0,0,mWidth,mHeight);

        canvas.drawBitmap(bitmap,null,rect,paint);
        return bitmapSrc;
    }
    /**
     * @param xA 起始点位置A的x轴绝对位置
     * @param yA 起始点位置A的y轴绝对位置
     * @param rFive 五角星边的边长
     */
    public static float[] fivePoints(float xA, float yA, int rFive) {
        float xB = 0;
        float xC = 0;
        float xD = 0;
        float xE = 0;
        float yB = 0;
        float yC = 0;
        float yD = 0;
        float yE = 0;
        xD = (float) (xA - rFive * Math.sin(Math.toRadians(18)));
        xC = (float) (xA + rFive * Math.sin(Math.toRadians(18)));
        yD = yC = (float) (yA + Math.cos(Math.toRadians(18)) * rFive);
        yB = yE = (float) (yA + Math.sqrt(Math.pow((xC - xD), 2) - Math.pow((rFive / 2), 2)));
        xB = xA + (rFive / 2);
        xE = xA - (rFive / 2);
        float[] floats = new float[]{xA, yA,  xD, yD,xB, yB, xE, yE, xC, yC,xA, yA};
        return floats;
    }

}
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:srcCompat="@drawable/test"/>
</android.support.constraint.ConstraintLayout>

参考链接:
Android Canvas之Path操作
https://www.jianshu.com/p/9ad3aaae0c63

android 五角星画法 五角星计算公式
https://blog.csdn.net/qq_15364915/article/details/75433651

94.通过PorterDuff模式改变tint属性叠加效果

<android.support.constraint.ConstraintLayout
    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">


    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="设置ADD模式"
        android:layout_marginLeft="16dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="8dp"/>

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="设置SRC_OUT模式"
        android:layout_marginRight="16dp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="8dp"/>

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="357dp"
        android:layout_height="374dp"
        app:srcCompat="@mipmap/flower"
        android:tint="@android:color/holo_green_dark"
        android:tintMode="multiply"
        android:layout_marginRight="8dp"
        app:layout_constraintRight_toRightOf="parent"
        android:layout_marginLeft="8dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="68dp"
        app:layout_constraintHorizontal_bias="0.545"/>
</android.support.constraint.ConstraintLayout>
public class MainActivity extends AppCompatActivity{
    private ImageView mImageView;
    private Bitmap mBitmap1;
    private Button mButton1;
    private Button mButton2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mImageView = (ImageView) findViewById(R.id.imageView);
        mButton1 = (Button) findViewById(R.id.button1);
        mButton1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mImageView.setImageTintMode(PorterDuff.Mode.ADD);
            }
        });
        mButton2 = (Button) findViewById(R.id.button2);
        mButton2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mImageView.setImageTintMode(PorterDuff.Mode.SRC_OUT);
            }
        });
    }
}

95.使用Region的DIFFERENCE实现抠图功能
clipRegion 废弃,clipPath(Path path, Op op)也废弃,因此跳过。但是六边形的画法值得一看。

image.png

参考链接:
Android 2D Graphics学习(二)、Canvas篇2、Canvas裁剪和Region、RegionIterator
https://blog.csdn.net/LonelyRoamer/article/details/8349601

Android中的裁剪中Region.Op参数的用法
https://blog.csdn.net/eyishion/article/details/53728913

Android画不规则形状
https://blog.csdn.net/foolish0421/article/details/78110362

Android自定义View——一个可定制的六边形阵列
https://www.jianshu.com/p/22c024726fa9
解决canvas.clipRegion 方法过时,实现裁剪减动画
https://blog.csdn.net/u010853130/article/details/85076887

96.使用ShapeDrawable裁剪三角形图像

<android.support.constraint.ConstraintLayout
    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">


    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="显示原始图像"
        android:layout_marginLeft="16dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="8dp"/>

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="显示三角形图像"
        android:layout_marginRight="16dp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="8dp"/>

    <ImageView
        android:id="@+id/imageView"
        android:background="@mipmap/flower"
        android:layout_width="357dp"
        android:layout_height="374dp"
        android:layout_marginRight="8dp"
        app:layout_constraintRight_toRightOf="parent"
        android:layout_marginLeft="8dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="68dp"
        app:layout_constraintHorizontal_bias="0.545"/>
</android.support.constraint.ConstraintLayout>
public class MainActivity extends AppCompatActivity{
    private ImageView mImageView;
    private Button mButton1;
    private Button mButton2;
    private Drawable mDrawable;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mDrawable = ResourcesCompat.getDrawable(getResources(),R.mipmap.flower,null);
        mImageView = (ImageView) findViewById(R.id.imageView);
        mButton1 = (Button) findViewById(R.id.button1);
        mButton1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mImageView.setBackground(mDrawable);
            }
        });
        mButton2 = (Button) findViewById(R.id.button2);
        mButton2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.flower);
                int width = bitmap.getWidth();
                Path path = new Path();
                path.moveTo(width/2,0);
                path.lineTo(mDrawable.getIntrinsicWidth(),mDrawable.getIntrinsicHeight());
                path.lineTo(0,mDrawable.getIntrinsicHeight());
                path.close();
                ShapeDrawable shapeDrawable = new ShapeDrawable(new PathShape(path,
                        mDrawable.getIntrinsicWidth(),mDrawable.getIntrinsicHeight()));
                BitmapShader bitmapShader = new BitmapShader(bitmap,Shader.TileMode.CLAMP,
                        Shader.TileMode.CLAMP);
                shapeDrawable.getPaint().setShader(bitmapShader);
                mImageView.setBackground(shapeDrawable);
            }
        });
    }
}

97.使用ClipDrawable裁剪图像实现星级评分
图片用画图工具随便画的,不是很整齐。


star.png
star_bg.png
<android.support.constraint.ConstraintLayout
    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">


    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="增加评分"
        android:layout_marginLeft="16dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="8dp"/>

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="减少评分"
        android:layout_marginRight="16dp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="8dp"/>

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="356dp"
        android:layout_height="153dp"
        android:scaleType="fitXY"
        android:background="@mipmap/star_bg"
        android:layout_marginRight="8dp"
        app:layout_constraintRight_toRightOf="parent"
        android:layout_marginLeft="8dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="93dp"/>


</android.support.constraint.ConstraintLayout>

public BitmapDrawable(Bitmap bitmap)废弃,改用public BitmapDrawable(Resources res, Bitmap bitmap)。


image.png
public class MainActivity extends AppCompatActivity{
    private Bitmap mBitmap;
    private ImageView mImageView;
    private Button mButton1;
    private Button mButton2;
    private ClipDrawable mClipDrawable;
    private int mLevel = 1000;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mImageView = (ImageView) findViewById(R.id.imageView);
        mBitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.star);
        mClipDrawable = new ClipDrawable(new BitmapDrawable(getResources(),mBitmap), Gravity.LEFT,ClipDrawable.HORIZONTAL);
        mImageView.setImageDrawable(mClipDrawable);
        mClipDrawable.setLevel(mLevel);

        mButton1 = (Button) findViewById(R.id.button1);
        mButton1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
              if (mLevel < 10000){
                  mClipDrawable.setLevel(mLevel += 2000);
              }
            }
        });
        mButton2 = (Button) findViewById(R.id.button2);
        mButton2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (mLevel > 0){
                    mClipDrawable.setLevel(mLevel -= 2000);
                }
            }
        });
    }
}

98.使用自定义Drawable实现对图像进行圆角

<android.support.constraint.ConstraintLayout
    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">


    <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="222dp"
        android:layout_marginTop="16dp"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@mipmap/image1"
        android:layout_marginStart="55dp"
        app:layout_constraintLeft_toLeftOf="parent"/>

    <ImageView
        android:id="@+id/imageView2"
        android:layout_width="192dp"
        android:layout_height="219dp"
        app:srcCompat="@mipmap/image2"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_marginBottom="31dp"
        android:layout_marginEnd="96dp"/>


</android.support.constraint.ConstraintLayout>
public class MainActivity extends AppCompatActivity{

    private ImageView mImageView1;
    private ImageView mImageView2;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mImageView1 = (ImageView) findViewById(R.id.imageView);
        mImageView2 = (ImageView) findViewById(R.id.imageView2);

        CircleRoundDrawable circleRoundDrawable1 = new CircleRoundDrawable(this,R.mipmap.image1);

        mImageView1.setImageDrawable(circleRoundDrawable1);
        CircleRoundDrawable circleRoundDrawable2 = new CircleRoundDrawable(this,R.mipmap.image2);
        circleRoundDrawable2.setType(1);
        circleRoundDrawable2.setRoundAngle(60);
        mImageView2.setImageDrawable(circleRoundDrawable2);

    }

    public class CircleRoundDrawable extends Drawable {

        private Paint paint;//画笔
        private int mWidth;//图片宽与高的最小值
        private RectF rectF;//矩形
        private int radius;//半径
        private int roundAngle = 30;//默认圆角
        private Bitmap bitmap;//位图
        private int type=2;//默认为圆形

        public static final int TYPE_Round = 1;
        public static final int Type_Circle = 2;


        public CircleRoundDrawable(Context context, int resID) {
            this(BitmapFactory.decodeResource(context.getResources(), resID));
        }

        public CircleRoundDrawable(Bitmap bitmap) {
            this.bitmap = bitmap;
            paint = new Paint();
            paint.setAntiAlias(true);//抗锯齿
            paint.setDither(true);//抖动,不同屏幕尺的使用保证图片质量

            ///位图渲染器
            BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
            paint.setShader(bitmapShader);
            mWidth = Math.min(bitmap.getWidth(), bitmap.getHeight());
            //初始化半径
            radius = mWidth / 2;
        }

        /***
         * 对外暴露的方法
         * @param roundAngle
         */
        public void setRoundAngle(int roundAngle) {
            this.roundAngle = roundAngle;
        }

        public void setType(int type) {
            this.type = type;
        }
        /**
         * drawable将被绘制在画布上的区域
         *
         * @param left
         * @param top
         * @param right
         * @param bottom
         */
        @Override
        public void setBounds(int left, int top, int right, int bottom) {
            super.setBounds(left, top, right, bottom);
            //绘制区域
            rectF = new RectF(left, top, right, bottom);
        }
        /**
         * 核心方法
         *
         * @param canvas
         */
        @Override
        public void draw(@NonNull Canvas canvas) {
            if (type ==Type_Circle) {
                canvas.drawCircle(mWidth / 2, mWidth / 2, radius, paint);
            } else{
                canvas.drawRoundRect(rectF, roundAngle, roundAngle, paint);
            }

        }

        @Override
        public void setAlpha(int i) {
            paint.setAlpha(i);
            invalidateSelf();//更新设置

        }

        @Override
        public int getIntrinsicHeight() {
            if (type == Type_Circle) {
                return mWidth;
            }
            return bitmap.getHeight();
        }

        @Override
        public int getIntrinsicWidth() {
            if (type == Type_Circle) {
                return mWidth;
            }
            return bitmap.getWidth();
        }

        @Override
        public void setColorFilter(@Nullable ColorFilter colorFilter) {
            paint.setColorFilter(colorFilter);
            invalidateSelf();//更行设置

        }

        @Override
        public int getOpacity() {
            return PixelFormat.TRANSLUCENT;
        }
    }



}

参考链接:
自定义Drawable完成圆形、圆角图片
https://www.jianshu.com/p/408cd4f32334

99.使用Matrix实现按照指定方向倾斜图像

public class MainActivity extends AppCompatActivity{
    private ImageView mImageView1;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mImageView1 = (ImageView) findViewById(R.id.imageView);
        mImageView1.setImageBitmap(getNewImage(BitmapFactory.decodeResource(getResources(),R.mipmap.image1)));


    }

    public Bitmap getNewImage(Bitmap bitmap){
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        Matrix matrix = new Matrix();
        matrix.postSkew(0.1f,0.2f);
        Bitmap newBitmap = Bitmap.createBitmap(bitmap,0,0,width,height,matrix,true);
        return newBitmap;
    }

}
<android.support.constraint.ConstraintLayout
    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">


    <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="222dp"
        android:layout_marginTop="16dp"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@mipmap/image1"
        android:layout_marginStart="55dp"
        app:layout_constraintLeft_toLeftOf="parent"/>



</android.support.constraint.ConstraintLayout>

参考链接:
Android ImageView通过Matrix实现图片倾斜效果
https://www.jianshu.com/p/2265b4f413d3
Matrix图片变换处理
https://www.jianshu.com/p/76686d1233d5

100.使用ColorMatrix为图像添加泛紫效果

<android.support.constraint.ConstraintLayout
    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">


    <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="222dp"
        android:layout_marginTop="16dp"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@mipmap/image1"
        android:layout_marginStart="55dp"
        app:layout_constraintLeft_toLeftOf="parent"/>



</android.support.constraint.ConstraintLayout>
public class MainActivity extends AppCompatActivity{
    private ImageView mImageView1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mImageView1 = (ImageView) findViewById(R.id.imageView);
        mImageView1.setImageBitmap(getNewImage(BitmapFactory.decodeResource(getResources(),R.mipmap.image1)));


    }

    public Bitmap getNewImage(Bitmap bitmap){
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
       float[] colorArray =  {1,0,11,0,10,
               0,1,0,0,100,
               0,100,1,0,0,
               0,0,0,1,0};
        Bitmap newBitmap = Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(newBitmap);
        Paint paint = new Paint();
        ColorMatrix colorMatrix = new ColorMatrix();
        colorMatrix.set(colorArray);
        paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
        canvas.drawBitmap(bitmap,0,0,paint);
        return newBitmap;
    }

}

参考链接:
Android自定义View之图像的色彩处理
https://www.jianshu.com/p/acf6bb2f5056
使用 ColorMatrix 对图片进行风格处理
https://blog.csdn.net/wufeng55/article/details/77488446
101.使用ColorMatrix实现图像的加暗效果

public class MainActivity extends AppCompatActivity{
    private ImageView mImageView1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mImageView1 = (ImageView) findViewById(R.id.imageView);
        mImageView1.setImageBitmap(getNewImage(BitmapFactory.decodeResource(getResources(),R.mipmap.image1)));


    }

    public Bitmap getNewImage(Bitmap bitmap){
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
       float[] colorArray =  {1,0,0,0,-100,
               0,1,0,0,-100,
               0,0,1,0,-100,
               0,0,0,1,0};
        Bitmap newBitmap = Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(newBitmap);
        Paint paint = new Paint();
        ColorMatrix colorMatrix = new ColorMatrix();
        colorMatrix.set(colorArray);
        paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
        canvas.drawBitmap(bitmap,0,0,paint);
        return newBitmap;
    }

}
<android.support.constraint.ConstraintLayout
    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">


    <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="222dp"
        android:layout_marginTop="16dp"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@mipmap/image1"
        android:layout_marginStart="55dp"
        app:layout_constraintLeft_toLeftOf="parent"/>



</android.support.constraint.ConstraintLayout>

102.通过自定义ColorMatrix调整图像蓝色色调

public class MainActivity extends AppCompatActivity{
    private ImageView mImageView1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mImageView1 = (ImageView) findViewById(R.id.imageView);
        mImageView1.setImageBitmap(getNewImage(BitmapFactory.decodeResource(getResources(),R.mipmap.image1)));


    }

    public Bitmap getNewImage(Bitmap bitmap){
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
       float[] colorArray =  {0,0,0,0,0,
               0,0,0,0,0,
               0,0,1,0,0,
               0,0,0,1,0};
        Bitmap newBitmap = Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(newBitmap);
        Paint paint = new Paint();
        ColorMatrix colorMatrix = new ColorMatrix();
        colorMatrix.set(colorArray);
        paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
        canvas.drawBitmap(bitmap,0,0,paint);
        return newBitmap;
    }

}
<android.support.constraint.ConstraintLayout
    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">


    <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="222dp"
        android:layout_marginTop="16dp"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@mipmap/image1"
        android:layout_marginStart="55dp"
        app:layout_constraintLeft_toLeftOf="parent"/>



</android.support.constraint.ConstraintLayout>

103.使用RenderScript实现高斯算法模糊图像

参考链接:
Android RenderScript 简单高效实现图片的高斯模糊效果
https://www.jianshu.com/p/b262b6ad3456

使用RenderScript实现高斯模糊(毛玻璃/磨砂)效果
https://www.jianshu.com/p/4d0176fd9730

104.使用拉普拉斯模板实现图像的锐化特效

参考链接:
android 图片处理器-包括反转、浮雕、锐化、轮廓提取功能
https://blog.csdn.net/qq_31785005/article/details/79050106
作者有附上github地址:
https://github.com/yaoMYZ/PictureProcessor

105.通过像素操作实现在图像上添加光照效果

参考链接:
Android图片特效处理(像素处理)
https://blog.csdn.net/qq_21430549/article/details/49635965

Android图像处理技巧理论
https://www.jianshu.com/p/49fc4dabb361

106.通过像素操作使彩色图像呈现浮雕特效
参考链接:
Android绘图机制与处理技巧——Android图像处理之色彩特效处理
https://www.jianshu.com/p/eade0041790f
Android图片特效处理(像素处理)
https://blog.csdn.net/qq_21430549/article/details/49635965

107.使用BitmapShader实现文字线条图像化

参考链接:
使用 Shader 填充颜色
https://blog.csdn.net/blueshell001/article/details/51760639
108.使用BlurMaskFilter为图像添加轮廓线
其实这种用法我没有找到应用场景,因为对图片的图层有要求。
下载图片。
https://www.easyicon.net/1217329-home_icon.html

home.png

public class MainActivity extends AppCompatActivity{
    private ImageView mImageView1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mImageView1 = (ImageView) findViewById(R.id.imageView);
        mImageView1.setImageBitmap(getNewImage(BitmapFactory.decodeResource(getResources(),R.mipmap.home)));

    }

    public Bitmap getNewImage(Bitmap bitmap){
        BlurMaskFilter blurMaskFilter = new BlurMaskFilter(10,BlurMaskFilter.Blur.OUTER);
        Paint paint = new Paint();
        paint.setColor(Color.RED);
        paint.setMaskFilter(blurMaskFilter);
        int[] offSet = new int[2];
        Bitmap image = bitmap.extractAlpha();//生成图像底片
        Bitmap imageCopy = image.copy(Bitmap.Config.ARGB_8888,true);
        Canvas canvas = new Canvas(imageCopy);
        canvas.drawBitmap(image,0,0,paint);//绘制底图和阴影
        canvas.drawBitmap(bitmap,-offSet[0],-offSet[1],null);//底图上绘制原图
        return imageCopy;
    }

}
<android.support.constraint.ConstraintLayout
    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">


    <ImageView
        android:id="@+id/imageView"
        android:layout_width="298dp"
        android:layout_height="187dp"
        android:layout_marginTop="16dp"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@mipmap/home"
        android:layout_marginRight="8dp"
        app:layout_constraintRight_toRightOf="parent"
        android:layout_marginLeft="8dp"
        app:layout_constraintLeft_toLeftOf="parent"/>

    <ImageView
        android:id="@+id/imageView2"
        android:layout_width="299dp"
        android:layout_height="196dp"
        app:srcCompat="@mipmap/home"
        android:layout_marginLeft="43dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_marginBottom="91dp"/>


</android.support.constraint.ConstraintLayout>

109.使用PathDashPathEffect实现椭圆线条
参考链接:
Android Paint之PathEffect(路径效果)
https://www.jianshu.com/p/4ef24f2c15b5

110.使用SumPathEffect叠加多种路径特效
参考链接:
自定义view(14)使用Path绘制复杂图形

111.通过BitmapShader实现以图像填充椭圆

Android之玩转View(二):使用Paint实现的特效(BitmapShader,LinearGradient,RadialGradient,SweepGradient)
https://www.jianshu.com/p/e8e97bda364b

112.使用ComposeShader创建渐变图像
下面文字出处:
https://www.jianshu.com/p/5fb82b189094

有五个类继承了Shader:
BitmapShader:位图图像渲染。
LinearGradient:线性渲染。
SweepGradient:渐变渲染/梯度渲染。
RadialGradient:环形渲染。
ComposeShader:组合渲染

ComposeShader会将两种渲染叠加。其构造函数如下。

    /** Create a new compose shader, given shaders A, B, and a combining mode.
        When the mode is applied, it will be given the result from shader A as its
        "dst", and the result from shader B as its "src".
        @param shaderA  The colors from this shader are seen as the "dst" by the mode
        @param shaderB  The colors from this shader are seen as the "src" by the mode
        @param mode     The mode that combines the colors from the two shaders. If mode
                        is null, then SRC_OVER is assumed.
    */
    public ComposeShader(Shader shaderA, Shader shaderB, Xfermode mode) {
        mType = TYPE_XFERMODE;
        mShaderA = shaderA;
        mShaderB = shaderB;
        mXferMode = mode;
        init(nativeCreate1(shaderA.getNativeInstance(), shaderB.getNativeInstance(),
                (mode != null) ? mode.native_instance : 0));
    }

    /** Create a new compose shader, given shaders A, B, and a combining PorterDuff mode.
        When the mode is applied, it will be given the result from shader A as its
        "dst", and the result from shader B as its "src".
        @param shaderA  The colors from this shader are seen as the "dst" by the mode
        @param shaderB  The colors from this shader are seen as the "src" by the mode
        @param mode     The PorterDuff mode that combines the colors from the two shaders.
    */
    public ComposeShader(Shader shaderA, Shader shaderB, PorterDuff.Mode mode) {
        mType = TYPE_PORTERDUFFMODE;
        mShaderA = shaderA;
        mShaderB = shaderB;
        mPorterDuffMode = mode;
        init(nativeCreate2(shaderA.getNativeInstance(), shaderB.getNativeInstance(),
                mode.nativeInt));
    }

参考链接:
Android高级渲染Shader(上)——基本用法
https://www.jianshu.com/p/5fb82b189094

113.使用ImageView显示XML实现的矢量图形
由于书中没有给出pathData的计算方法,因此此实例不具备扩展性,所以直接找了网上的例子。
参考链接:
Android 使用Vector XML文件创建矢量图片资源
https://blog.csdn.net/klxh2009/article/details/51121034

Android使用矢量图(SVG, VectorDrawable)实践篇
https://www.jianshu.com/p/0555b8c1d26a

114.使用BitmapFactory压缩图像的大小
Bitmap使用过程中还是比较容易出现内存泄漏的,这里面的坑踩过了就知道了。
下面的链接解释较为详细。
参考链接:
Android之Bitmap总结(加载、尺寸压缩、优化)
https://www.jianshu.com/p/c77158b6e07e

115.在自定义类中使用Movie显示动态图像

参考链接:
自定义显示动态图的Android控件
https://blog.csdn.net/xiaoshubing/article/details/50979485
116.通过使用图像作为画布创建带水印图像

参考链接:
Android给图片添加文字和水印
https://www.jianshu.com/p/c6099602f70c
实际上,根据我目前使用中所遇到的图片处理方面的问题来说,用ndk的方式去实现的话的确会减少很多内存泄漏的风险,而且会更高效。

117.通过操作根布局实现将屏幕内容保存为图像
主要是通过loadBitmapFromView。
参考链接:
关于View转化成bitmap保存成图片

118.通过手势变化实现平移旋转缩放图像
下面的链接解说比较详细,所以抛弃了书上的代码。
参考链接:
自定义可旋转、平移、缩放的ImageView
https://www.jianshu.com/p/938ca88fb16a

119.使用ThumbnailUtils提取大图像的缩略图
关键代码:
public static Bitmap extractThumbnail(Bitmap source, int width, int height)
参考链接:
聊聊Android中Bitmap缩放
https://www.jianshu.com/p/abcfa74c967b

120.通过采用取模的方式实现轮流显示多幅图像
其实这就是一个无限轮播的例子。
通常取图使用条件语句判断是否到达数组的末端,但是按书上的意思是通过取模,会更高效。

public class MainActivity extends AppCompatActivity{
    private int[] mImages = new int[]{R.mipmap.image1,R.mipmap.image2,R.mipmap.image3};
    private int mCurrent;
    private ImageView mImageView1;
    private Handler mHandler =  new Handler(){
        public void handleMessage(Message msg){
            if (msg.what == 1){
                mImageView1.setImageResource(mImages[++mCurrent % mImages.length]);
            }
            super.handleMessage(msg);
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mImageView1 = (ImageView) findViewById(R.id.imageView);
        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                mHandler.sendEmptyMessage(1);
            }
        },0,2000);

    }

}

<android.support.constraint.ConstraintLayout
    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">


    <ImageView
        android:id="@+id/imageView"
        android:layout_width="298dp"
        android:layout_height="187dp"
        android:layout_marginTop="16dp"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@mipmap/image1"
        android:layout_marginRight="8dp"
        app:layout_constraintRight_toRightOf="parent"
        android:layout_marginLeft="8dp"
        app:layout_constraintLeft_toLeftOf="parent"/>

</android.support.constraint.ConstraintLayout>
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,271评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,725评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,252评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,634评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,549评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,985评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,471评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,128评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,257评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,233评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,235评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,940评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,528评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,623评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,858评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,245评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,790评论 2 339

推荐阅读更多精彩内容