两种不切图就可以改变自定义控件颜色的办法

产品给我推了这么一个图:

要我根据选择的色板的颜色改变画笔图标的颜色,然后给我预留了这么一堆图标:

        然后我感到密集恐惧症爆发,而且表示不想加这么多Logo进去应用里面增肥。所以我想了大概1分钟,觉得既然Logo都是一样的轮廓只是颜色不一样,那么我可以把白色的Logo拿出来,分别按比例削弱或者增强每个像素的透明度、红绿蓝属性即可动态地使View里面的图标颜色从初始化的白色变化为任意的颜色。

      原来就是通过位运算,把每个像素的ARGB 4个字节拆分,分别乘以不同的百分比,从而使某些颜色相对削弱和相对增强,重新混合后就是不同的颜色了,例如0xFFFFFFFF,第二个字节的FF乘以0.5,最后两个字节乘以0,就可以得到暗红色;RGB全部乘以0,则得到黑色。

      具体实现代码可以看我的自定义控件Demo类,图片素材可以自己找其他其他白色图片:

package test.graphics;

import android.annotation.Nullable;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;


import java.nio.IntBuffer;

import cjz.project.maptry.R;

/**
 * Created by cjz on 2019/8/8.
 */

public class PenButton extends View {
    private int color = Color.WHITE;
    private int id = R.drawable.pen_first_kind_philips;

    public PenButton(Context context) {
        super(context);
    }

    public PenButton(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

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

    /**设置颜色**/
    public void setColor(int color){
        this.color = color;
        invalidate();
    }

    public void setDrawableID(int id){
        this.id = id;
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), id);
        int pixels[] = new int[bitmap.getHeight() * bitmap.getWidth()];
        //复制像素出来
        bitmap.copyPixelsToBuffer(IntBuffer.wrap(pixels));
        //计算颜色通道
        int color = (this.color & 0xFF00FF00              //alpha和green排列一致直接或运算取值
                | this.color >> 16 & 0x000000FF         //blue位移16bit到最后一字节,或运算保存到最后一字节
                | this.color << 16 & 0x00FF0000);       //red位移16bit到第二个字节,或运算保存到第二个字节
        float alpha = ((color >> 24) & 0xFF) / 255f;
        float rChannelAlpha = ((color >> 16) & 0xFF) / 255f * alpha;
        float gChannelAlpha = ((color >> 8) & 0xFF) / 255f * alpha;
        float bChannelAlpha = ((color) & 0xFF) / 255f * alpha;
        //对图像进行单一颜色通道过滤(其实就是按color的颜色通道按比例决定保留哪种颜色,还有保留多少比例)
        for(int i = 0; i < pixels.length; i ++){
            int newA = (int)(((pixels[i] >> 24) & 0xFF) * alpha);
            int newR = (int)(((pixels[i] >> 16) & 0xFF) * rChannelAlpha);
            int newG = (int)(((pixels[i] >> 8) & 0xFF) * gChannelAlpha);
            int newB = (int)(((pixels[i]) & 0xFF) * bChannelAlpha);
            pixels[i] = 0;
            //载入新颜色
            pixels[i] |= (newA << 24);
            pixels[i] |= (newR << 16);
            pixels[i] |= (newG << 8);
            pixels[i] |= newB;
        }
        bitmap.copyPixelsFromBuffer(IntBuffer.wrap(pixels));
        canvas.drawBitmap(bitmap, new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()),new Rect(0, 0, getWidth(), getHeight()), null);
        super.onDraw(canvas);
    }
}

布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="@mipmap/ic_launcher">

    <test.graphics.PenButton
        android:id="@+id/pb_test_button"
        android:layout_width="50dp"
        android:layout_height="200dp"
        android:layout_gravity="center_horizontal"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#FFFFFFFF"
        android:text="透明度"/>

    <SeekBar
        android:id="@+id/alpha_channel"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:progress="255"
        android:max="255"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#FFFFFFFF"
        android:text="红"/>

    <SeekBar
        android:id="@+id/r_channel"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:progress="255"
        android:max="255"/>


    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#FFFFFFFF"
        android:text="绿"/>

    <SeekBar
        android:id="@+id/g_channel"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:progress="255"
        android:max="255"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#FFFFFFFF"
        android:text="蓝"/>

    <SeekBar
        android:id="@+id/b_channel"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:progress="255"
        android:max="255"/>
</LinearLayout>

 

MainActivity:

       其中诸如color ^= 0xFF000000 & color; 这类代码,实际上是先通过与运算只保留要消除的像素颜色分量, 再通过异或运算抵消color变量原本该分量的所有1,达到清空该分量颜色的目的。

package test.graphics;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.SeekBar;

import cjz.project.maptry.R;

/**
 * Created by cjz on 2019/8/8.
 */

public class MainActivity extends Activity{
    private PenButton pb_test_button;
    private SeekBar alpha_channel;
    private SeekBar r_channel;
    private SeekBar g_channel;
    private SeekBar b_channel;
    private int color = 0xFFFFFFFF;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test_change_color_button);
        pb_test_button = findViewById(R.id.pb_test_button);
        alpha_channel = findViewById(R.id.alpha_channel);
        r_channel = findViewById(R.id.r_channel);
        g_channel = findViewById(R.id.g_channel);
        b_channel = findViewById(R.id.b_channel);
        SeekBar.OnSeekBarChangeListener onSeekBarChangeListener = new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                if (seekBar.getId() == alpha_channel.getId()){
                    color ^= 0xFF000000 & color; //清空透明度
                    color |= ((progress & 0xFF) << 24); //给新的透明度
                } else if (seekBar.getId() == r_channel.getId()) {
                    color ^= 0x00FF0000 & color;
                    color |= ((progress & 0xFF) << 16);
                } else if (seekBar.getId() == g_channel.getId()) {
                    color ^= 0x0000FF00 & color;
                    color |= ((progress & 0xFF) << 8);
                } else if (seekBar.getId() == b_channel.getId()) {
                    color ^= 0x000000FF & color;
                    color |= progress & 0xFF ;
                }
                Log.i("progress", "" + progress);
                Log.i("color", String.format("0x%8X", color));
                pb_test_button.setColor(color);
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {

            }
        };
        alpha_channel.setOnSeekBarChangeListener(onSeekBarChangeListener);
        r_channel.setOnSeekBarChangeListener(onSeekBarChangeListener);
        g_channel.setOnSeekBarChangeListener(onSeekBarChangeListener);
        b_channel.setOnSeekBarChangeListener(onSeekBarChangeListener);


    }
}

 

实现效果

 

然后因为我自己写这个东西比查资料来得更快,所以完成任务之后查了一下其实会不会安卓SDK自身就能做到这个事情,发现其实是可以的,方法我直接粘贴别人的文章好了:

 

https://www.jianshu.com/p/6a781c6203fe

https://blog.csdn.net/qq_32452623/article/details/79878132

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值