Android
1.1 背景相关与系统架构分析 1.2 开发环境搭建 1.2.1 使用Eclipse + ADT + SDK开发Android APP 1.2.2 使用Android Studio开发Android APP 1.3 SDK更新不了问题解决 1.4 Genymotion模拟器安装 1.5.1 Git使用教程之本地仓库的基本操作 1.5.2 Git之使用GitHub搭建远程仓库 1.6 .9(九妹)图片怎么玩 1.7 界面原型设计 1.8 工程相关解析(各种文件,资源访问) 1.9 Android程序签名打包 1.11 反编译APK获取代码&资源 2.1 View与ViewGroup的概念 2.2.1 LinearLayout(线性布局) 2.2.2 RelativeLayout(相对布局) 2.2.3 TableLayout(表格布局) 2.2.4 FrameLayout(帧布局) 2.2.5 GridLayout(网格布局) 2.2.6 AbsoluteLayout(绝对布局) 2.3.1 TextView(文本框)详解 2.3.2 EditText(输入框)详解 2.3.3 Button(按钮)与ImageButton(图像按钮) 2.3.4 ImageView(图像视图) 2.3.5.RadioButton(单选按钮)&Checkbox(复选框) 2.3.6 开关按钮ToggleButton和开关Switch 2.3.7 ProgressBar(进度条) 2.3.8 SeekBar(拖动条) 2.3.9 RatingBar(星级评分条) 2.4.1 ScrollView(滚动条) 2.4.2 Date & Time组件(上) 2.4.3 Date & Time组件(下) 2.4.4 Adapter基础讲解 2.4.5 ListView简单实用 2.4.6 BaseAdapter优化 2.4.7ListView的焦点问题 2.4.8 ListView之checkbox错位问题解决 2.4.9 ListView的数据更新问题 2.5.0 构建一个可复用的自定义BaseAdapter 2.5.1 ListView Item多布局的实现 2.5.2 GridView(网格视图)的基本使用 2.5.3 Spinner(列表选项框)的基本使用 2.5.4 AutoCompleteTextView(自动完成文本框)的基本使用 2.5.5 ExpandableListView(可折叠列表)的基本使用 2.5.6 ViewFlipper(翻转视图)的基本使用 2.5.7 Toast(吐司)的基本使用 2.5.8 Notification(状态栏通知)详解 2.5.9 AlertDialog(对话框)详解 2.6.0 其他几种常用对话框基本使用 2.6.1 PopupWindow(悬浮框)的基本使用 2.6.2 菜单(Menu) 2.6.3 ViewPager的简单使用 2.6.4 DrawerLayout(官方侧滑菜单)的简单使用 3.1.1 基于监听的事件处理机制 3.2 基于回调的事件处理机制 3.3 Handler消息传递机制浅析 3.4 TouchListener PK OnTouchEvent + 多点触碰 3.5 监听EditText的内容变化 3.6 响应系统设置的事件(Configuration类) 3.7 AnsyncTask异步任务 3.8 Gestures(手势) 4.1.1 Activity初学乍练 4.1.2 Activity初窥门径 4.1.3 Activity登堂入室 4.2.1 Service初涉 4.2.2 Service进阶 4.2.3 Service精通 4.3.1 BroadcastReceiver牛刀小试 4.3.2 BroadcastReceiver庖丁解牛 4.4.1 ContentProvider初探 4.4.2 ContentProvider再探——Document Provider 4.5.1 Intent的基本使用 4.5.2 Intent之复杂数据的传递 5.1 Fragment基本概述 5.2.1 Fragment实例精讲——底部导航栏的实现(方法1) 5.2.2 Fragment实例精讲——底部导航栏的实现(方法2) 5.2.3 Fragment实例精讲——底部导航栏的实现(方法3) 5.2.4 Fragment实例精讲——底部导航栏+ViewPager滑动切换页面 5.2.5 Fragment实例精讲——新闻(购物)类App列表Fragment的简单实现 6.1 数据存储与访问之——文件存储读写 6.2 数据存储与访问之——SharedPreferences保存用户偏好参数 6.3.1 数据存储与访问之——初见SQLite数据库 6.3.2 数据存储与访问之——又见SQLite数据库 7.1.1 Android网络编程要学的东西与Http协议学习 7.1.2 Android Http请求头与响应头的学习 7.1.3 Android HTTP请求方式:HttpURLConnection 7.1.4 Android HTTP请求方式:HttpClient 7.2.1 Android XML数据解析 7.2.2 Android JSON数据解析 7.3.1 Android 文件上传 7.3.2 Android 文件下载(1) 7.3.3 Android 文件下载(2) 7.5.1 WebView(网页视图)基本用法 7.5.2 WebView和JavaScrip交互基础 7.5.3 Android 4.4后WebView的一些注意事项 7.5.4 WebView文件下载 7.5.5 WebView缓存问题 7.5.6 WebView处理网页返回的错误码信息 7.6.1 Socket学习网络基础准备 7.6.2 基于TCP协议的Socket通信(1) 7.6.3 基于TCP协议的Socket通信(2) 7.6.4 基于UDP协议的Socket通信 8.1.1 Android中的13种Drawable小结 Part 1 8.1.2 Android中的13种Drawable小结 Part 2 8.1.3 Android中的13种Drawable小结 Part 3 8.2.1 Bitmap(位图)全解析 Part 1 8.2.2 Bitmap引起的OOM问题 8.3.1 三个绘图工具类详解 8.3.2 绘图类实战示例 8.3.3 Paint API之—— MaskFilter(面具) 8.3.4 Paint API之—— Xfermode与PorterDuff详解(一) 8.3.5 Paint API之—— Xfermode与PorterDuff详解(二) 8.3.6 Paint API之—— Xfermode与PorterDuff详解(三) 8.3.7 Paint API之—— Xfermode与PorterDuff详解(四) 8.3.8 Paint API之—— Xfermode与PorterDuff详解(五) 8.3.9 Paint API之—— ColorFilter(颜色过滤器)(1/3) 8.3.10 Paint API之—— ColorFilter(颜色过滤器)(2-3) 8.3.11 Paint API之—— ColorFilter(颜色过滤器)(3-3) 8.3.12 Paint API之—— PathEffect(路径效果) 8.3.13 Paint API之—— Shader(图像渲染) 8.3.14 Paint几个枚举/常量值以及ShadowLayer阴影效果 8.3.15 Paint API之——Typeface(字型) 8.3.16 Canvas API详解(Part 1) 8.3.17 Canvas API详解(Part 2)剪切方法合集 8.3.18 Canvas API详解(Part 3)Matrix和drawBitmapMash 8.4.1 Android动画合集之帧动画 8.4.2 Android动画合集之补间动画 8.4.3 Android动画合集之属性动画-初见 8.4.4 Android动画合集之属性动画-又见 9.1 使用SoundPool播放音效(Duang~) 9.2 MediaPlayer播放音频与视频 10.1 TelephonyManager(电话管理器) 10.2 SmsManager(短信管理器) 10.3 AudioManager(音频管理器) 10.4 Vibrator(振动器) 10.5 AlarmManager(闹钟服务) 10.6 PowerManager(电源服务) 10.7 WindowManager(窗口管理服务) 10.8 LayoutInflater(布局服务) 10.9 WallpaperManager(壁纸管理器) 10.10 传感器专题(1)——相关介绍 10.11 传感器专题(2)——方向传感器 10.12 传感器专题(3)——加速度/陀螺仪传感器

8.3.2 绘图类实战示例

本节引言:

前两节我们学了Bitmap和一些基本的绘图API的属性以及常用的方法,但心里总觉得有点 不踏实,总得写点什么加深下映像是吧,嗯,本节我们就来写两个简单的例子:

  • 1.简单画图板的实现
  • 2.帮美女擦衣服的简单实现

嘿嘿,第二个例子是小猪刚学安卓写的一个小Demo~嘿嘿~ 开始本节内容~


1.实战示例1:简单画图板的实现:

这个相信大家都不陌生,很多手机都会自带一个给用户涂鸦的画图板,这里我们就来写个简单的 例子,首先我们分析下,实现这个东东的一些逻辑:

Q1:这个画板放在哪里?

答:View里,我们自定义一个View,在onDraw()里完成绘制,另外View还有个onTouchEvent的方法, 我们可以在获取用户的手势操作!

Q2.需要准备些什么?

答:一只画笔(Paint),一块画布(Canvas),一个路径(Path)记录用户绘制路线; 另外划线的时候,每次都是从上次拖动时间的发生点到本次拖动时间的发生点!那么之前绘制的 就会丢失,为了保存之前绘制的内容,我们可以引入所谓的"双缓冲"技术: 其实就是每次不是直接绘制到Canvas上,而是先绘制到Bitmap上,等Bitmap上的绘制完了, 再一次性地绘制到View上而已!

Q3.具体的实现流程?

答:初始化画笔,设置颜色等等一些参数;在View的onMeasure()方法中创建一个View大小的Bitmap, 同时创建一个Canvas;onTouchEvent中获得X,Y坐标,做绘制连线,最后invalidate()重绘,即调用 onDraw方法将bitmap的东东画到Canvas上!

好了,逻辑知道了,下面就上代码了:

MyView.java

/**
 * Created by Jay on 2015/10/15 0015.
 */
public class MyView extends View{

    private Paint mPaint;  //绘制线条的Path
    private Path mPath;      //记录用户绘制的Path
    private Canvas mCanvas;  //内存中创建的Canvas
    private Bitmap mBitmap;  //缓存绘制的内容

    private int mLastX;
    private int mLastY;

    public MyView(Context context) {
        super(context);
        init();
    }

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init(){
        mPath = new Path();
        mPaint = new Paint();   //初始化画笔
        mPaint.setColor(Color.GREEN);
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND); //结合处为圆角
        mPaint.setStrokeCap(Paint.Cap.ROUND); // 设置转弯处为圆角
        mPaint.setStrokeWidth(20);   // 设置画笔宽度
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = getMeasuredWidth();
        int height = getMeasuredHeight();
        // 初始化bitmap,Canvas
        mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(mBitmap);
    }

    //重写该方法,在这里绘图
    @Override
    protected void onDraw(Canvas canvas) {
        drawPath();
        canvas.drawBitmap(mBitmap, 0, 0, null);
    }

    //绘制线条
    private void drawPath(){
        mCanvas.drawPath(mPath, mPaint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        int action = event.getAction();
        int x = (int) event.getX();
        int y = (int) event.getY();

        switch (action)
        {
            case MotionEvent.ACTION_DOWN:
                mLastX = x;
                mLastY = y;
                mPath.moveTo(mLastX, mLastY);
                break;
            case MotionEvent.ACTION_MOVE:
                int dx = Math.abs(x - mLastX);
                int dy = Math.abs(y - mLastY);
                if (dx > 3 || dy > 3)
                    mPath.lineTo(x, y);
                mLastX = x;
                mLastY = y;
                break;
        }

        invalidate();
        return true;
    }
}

运行效果图

你可以根据自己的需求进行扩展,比如加上修改画笔大小,修改画笔颜色,保存自己画的图等! 发散思维,自己动手~


2.实战示例2:擦掉美女衣服的实现

核心思路是: 利用帧布局,前后两个ImageView,前面的显示未擦掉衣服的情况,后面的显示擦掉衣服后的情况!

为两个ImageView设置美女图片后,接着为前面的ImageView设置OnTouchListener!在这里对手指 触碰点附近的20*20个像素点,设置为透明!

运行效果图

代码实现

Step 1:第一个选妹子的Activity相关的编写,首先是界面,一个ImageView,Button和Gallery!

activity_main.xml

<?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">

    <ImageView
        android:id="@+id/img_choose"
        android:layout_width="320dp"
        android:layout_height="320dp" />

    <Button
        android:id="@+id/btn_choose"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="脱光她!" />

    <Gallery
        android:id="@+id/gay_choose"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="25dp"
        android:spacing="1pt"
        android:unselectedAlpha="0.6" />

</LinearLayout>

接着是我们Gallery的Adapter类,这里我们重写下BaseAdapter,而里面就显示一个图片比较简单, 就不另外写一个布局了!

MeiziAdapter.java:

/**
 * Created by Jay on 2015/10/16 0016.
 */
public class MeiziAdapter extends BaseAdapter{

    private Context mContext;
    private int[] mData;

    public MeiziAdapter() {
    }

    public MeiziAdapter(Context mContext,int[] mData) {
        this.mContext = mContext;
        this.mData = mData;
    }

    @Override
    public int getCount() {
        return mData.length;
    }

    @Override
    public Object getItem(int position) {
        return mData[position];
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ImageView imgMezi = new ImageView(mContext);
        imgMezi.setImageResource(mData[position]);         //创建一个ImageView
        imgMezi.setScaleType(ImageView.ScaleType.FIT_XY);      //设置imgView的缩放类型
        imgMezi.setLayoutParams(new Gallery.LayoutParams(250, 250));    //为imgView设置布局参数
        TypedArray typedArray = mContext.obtainStyledAttributes(R.styleable.Gallery);
        imgMezi.setBackgroundResource(typedArray.getResourceId(R.styleable.Gallery_android_galleryItemBackground, 0));
        return imgMezi;
    }
}

最后到我们的Activity,也很简单,无非是为gallery设置onSelected事件,点击按钮后把,当前选中的 Position传递给下一个页面!

MainActivity.java

public class MainActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener,
        View.OnClickListener {

    private Context mContext;
    private ImageView img_choose;
    private Button btn_choose;
    private Gallery gay_choose;
    private int index = 0;
    private MeiziAdapter mAdapter = null;
    private int[] imageIds = new int[]
            {
                    R.mipmap.pre1, R.mipmap.pre2, R.mipmap.pre3, R.mipmap.pre4,
                    R.mipmap.pre5, R.mipmap.pre6, R.mipmap.pre7, R.mipmap.pre8,
                    R.mipmap.pre9, R.mipmap.pre10, R.mipmap.pre11, R.mipmap.pre12,
                    R.mipmap.pre13, R.mipmap.pre14, R.mipmap.pre15, R.mipmap.pre16,
                    R.mipmap.pre17, R.mipmap.pre18, R.mipmap.pre19, R.mipmap.pre20,
                    R.mipmap.pre21
            };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mContext = MainActivity.this;
        bindViews();
    }

    private void bindViews() {
        img_choose = (ImageView) findViewById(R.id.img_choose);
        btn_choose = (Button) findViewById(R.id.btn_choose);
        gay_choose = (Gallery) findViewById(R.id.gay_choose);


        mAdapter = new MeiziAdapter(mContext, imageIds);
        gay_choose.setAdapter(mAdapter);
        gay_choose.setOnItemSelectedListener(this);
        btn_choose.setOnClickListener(this);

    }


    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        img_choose.setImageResource(imageIds[position]);
        index = position;
    }

    @Override
    public void onNothingSelected(AdapterView<?> parent) {
    }

    @Override
    public void onClick(View v) {
        Intent it = new Intent(mContext,CaClothes.class);
        Bundle bundle = new Bundle();
        bundle.putCharSequence("num", Integer.toString(index));
        it.putExtras(bundle);
        startActivity(it);
    }
}

接着是我们擦掉妹子衣服的页面了,布局比较简单,FrameLayout + 前后两个ImageView:

activity_caclothes.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/img_after"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <ImageView
        android:id="@+id/img_before"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</FrameLayout>

接着到就到Java部分的代码了:

CaClothes.java

/**
 * Created by Jay on 2015/10/16 0016.
 */
public class CaClothes extends AppCompatActivity implements View.OnTouchListener {

    private ImageView img_after;
    private ImageView img_before;
    private Bitmap alterBitmap;
    private Canvas canvas;
    private Paint paint;
    private Bitmap after;
    private Bitmap before;
    private int position;

    int[] imageIds1 = new int[]
            {
                    R.mipmap.pre1, R.mipmap.pre2, R.mipmap.pre3, R.mipmap.pre4,
                    R.mipmap.pre5, R.mipmap.pre6, R.mipmap.pre7, R.mipmap.pre8,
                    R.mipmap.pre9, R.mipmap.pre10, R.mipmap.pre11, R.mipmap.pre12,
                    R.mipmap.pre13, R.mipmap.pre14, R.mipmap.pre15, R.mipmap.pre16,
                    R.mipmap.pre17, R.mipmap.pre18, R.mipmap.pre19, R.mipmap.pre20,
                    R.mipmap.pre21
            };


    int[] imageIds2 = new int[]
            {
                    R.mipmap.after1, R.mipmap.after2, R.mipmap.after3, R.mipmap.after4,
                    R.mipmap.after5, R.mipmap.after6, R.mipmap.after7, R.mipmap.after8,
                    R.mipmap.after9, R.mipmap.after10, R.mipmap.after11, R.mipmap.after12,
                    R.mipmap.after13, R.mipmap.after14, R.mipmap.after15, R.mipmap.after16,
                    R.mipmap.after17, R.mipmap.after18, R.mipmap.after19, R.mipmap.after20,
                    R.mipmap.after21
            };


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_caclothes);

        Bundle bd = getIntent().getExtras();
        position = Integer.parseInt(bd.getString("num"));
        bindViews();

    }

    private void bindViews() {
        img_after = (ImageView) findViewById(R.id.img_after);
        img_before = (ImageView) findViewById(R.id.img_before);


        BitmapFactory.Options opts = new BitmapFactory.Options();
        opts.inSampleSize = 1;
        after = BitmapFactory.decodeResource(getResources(), imageIds2[position], opts);
        before = BitmapFactory.decodeResource(getResources(), imageIds1[position], opts);
        //定义出来的是只读图片

        alterBitmap = Bitmap.createBitmap(before.getWidth(), before.getHeight(), Bitmap.Config.ARGB_4444);
        canvas = new Canvas(alterBitmap);
        paint = new Paint();
        paint.setStrokeCap(Paint.Cap.ROUND);
        paint.setStrokeJoin(Paint.Join.ROUND);
        paint.setStrokeWidth(5);
        paint.setColor(Color.BLACK);
        paint.setAntiAlias(true);
        canvas.drawBitmap(before, new Matrix(), paint);
        img_after.setImageBitmap(after);
        img_before.setImageBitmap(before);
        img_before.setOnTouchListener(this);
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                break;
            case MotionEvent.ACTION_MOVE:
                int newX = (int) event.getX();
                int newY = (int) event.getY();
                //setPixel方法是将某一个像素点设置成一个颜色,而这里我们把他设置成透明
                //另外通过嵌套for循环将手指触摸区域的20*20个像素点设置为透明
                for (int i = -20; i < 20; i++) {
                    for (int j = -20; j < 20; j++) {
                        if (i + newX >= 0 && j + newY >= 0 && i + newX < before.getWidth() && j + newY < before.getHeight())
                            alterBitmap.setPixel(i + newX, j + newY, Color.TRANSPARENT);
                    }
                }
                img_before.setImageBitmap(alterBitmap);
                break;
        }
        return true;
    }
}

代码也不算苦涩难懂,还是比较简单的哈,嗯,效果图看看就好,别做那么多右手螺旋定则哈....


本节小结:

好的,本节写了关于绘图的两个小例子,还是蛮有趣的,相信你发下了,擦美女衣服那里, 消除的时候是方块的,不那么完美是吧,没事,下节我们学多个PorterDuff这个东西,我们 再来写多个例子,相比起这个代码就简单很多了,另外,时间关系,代码并没有去优化 或者整理,可以根据自己需求进行修改~好的,就说这么多,祝大家周末愉快~

© 2021 jiaocheng.bubufx.com  联系我们
ICP备案:鲁ICP备09046678号-3