Android 知识点

FrameLayout(帧布局)

常用属性

FrameLayout的属性很少就两个,但是在说之前我们先介绍一个东西:

前景图像:永远处于帧布局最上面,直接面对用户的图像,就是不会被覆盖的图片。

两个属性:

  • android:foreground:*设置改帧布局容器的前景图像
  • android:foregroundGravity:设置前景图像显示的位置

TableLayout(表格布局)

常用属性

android:collapseColumns:设置需要被隐藏的列的序号
android:shrinkColumns:设置允许被收缩的列的列序号
android:stretchColumns:设置运行被拉伸的列的列序号

以上这三个属性的列号都是从0开始算的,比如shrinkColunmns ="2",对应的是第三列!
可以设置多个,用逗号隔开比如"0,2",如果是所有列都生效,则用"*"号即可
除了这三个常用属性,还有两个属性,分别就是跳格子以及合并单元格,这和HTML中的Table类似:

android:layout_column="2":表示的就是跳过第二个,直接显示到第三个格子处,从1开始算的!
android:layout_span="4":表示合并4个单元格,也就说这个组件占4个单元格

RelativeLayout(相对布局)

 

 

LinearLayout(线性布局)

 

 

 

 

listview作为一个列表控件,他和普通的列表一样,可以自己设置表头与表尾: 以及分割线,可供我们设置的属性如下:

·        footerDividersEnabled:是否在footerView(表尾)前绘制一个分隔条,默认为true

·        headerDividersEnabled:是否在headerView(表尾)前绘制一个分隔条,默认为true

·        divider:设置分隔条,可以用颜色分割,也可以用drawable资源分割

·        dividerHeight:设置分隔条的高度

翻遍了了API发现并没有可以直接设置ListView表头或者表尾的属性,只能在Java中写代码 进行设置了,可供我们调用的方法如下:

·        addHeaderView(View v):添加headView(表头),括号中的参数是一个View对象

·        addFooterView(View v):添加footerView(表尾),括号中的参数是一个View对象

·        addHeaderView(headView, null, false):和前面的区别:设置Header是否可以被选中

·        addFooterView(View,view,false):同上

对了,使用这个addHeaderView方法必须放在listview.setAdapter前面,否则会报错。

4.设置点击颜色cacheColorHint

如果你为ListView设置了一个图片作为Background的话,当你拖动或者点击listView空白位置会发现 item都变成黑色了,这是时候我们可以通过这个cacheColorHint将颜色设置为透明:#00000000


5.隐藏滑动条

我们可以通过设置:android:scrollbars="none" 或者setVerticalScrollBarEnabled(true); 解决这个问题!

3.列表从底部开始显示:stackFromBottom

如果你想让列表显示你列表的最下面的话,那么你可以使用这个属性,将stackFromBottom 属性设置为true即可,设置后的效果图如下:

ViewHolder重用组件

嘿嘿,getView()会被调用多次,那么findViewById不一样得调用多次,而我们的ListView的Item 一般都是一样的布局,我们可以对这里在优化下,我们可以自己定义一个ViewHolder类来对这一部分 进行性能优化!修改后的代码如下:

@Override

public View getView(intposition, View convertView, ViewGroup parent) {

    ViewHolder holder = null;

    if(convertView == null){

        convertView =LayoutInflater.from(mContext).inflate(R.layout.item_list_animal,parent,false);

        holder = new ViewHolder();

        holder.img_icon = (ImageView) convertView.findViewById(R.id.img_icon);

        holder.txt_aName = (TextView)convertView.findViewById(R.id.txt_aName);

        holder.txt_aSpeak = (TextView)convertView.findViewById(R.id.txt_aSpeak);

        convertView.setTag(holder);   //将Holder存储到convertView中

    }else{

        holder = (ViewHolder)convertView.getTag();

    }

   holder.img_icon.setBackgroundResource(mData.get(position).getaIcon());

   holder.txt_aName.setText(mData.get(position).getaName());

   holder.txt_aSpeak.setText(mData.get(position).getaSpeak());

    return convertView;

}

 

static class ViewHolder{

    ImageView img_icon;

    TextView txt_aName;

    TextView txt_aSpeak;

}

没错就是这么简单,你以后BaseAdapter照着这个模板写就对了,哈哈,另外这个修饰ViewHolder的 static,关于是否定义成静态,跟里面的对象数目是没有关系的,加静态是为了在多个地方使用这个 Holder的时候,类只需加载一次,如果只是使用了一次,加不加也没所谓!——Berial(B神)原话~

 

 

 

WebView文件下载

1.调用其它浏览器下载文件:

这个很简单,我们只需为WebView设置setDownloadListener,然后重写DownloadListener的 onDownloadStart,然后在里面写个Intent,然后startActivity对应的Activity即可!

关键代码如下

wView.setDownloadListener(new DownloadListener(){

@Override

public voidonDownloadStart(String url, String userAgent, String contentDisposition,

               String mimetype, long contentLength) {

        Log.e("HEHE","开始下载");

        Uri uri = Uri.parse(url);

        Intent intent = new Intent(Intent.ACTION_VIEW,uri);

        startActivity(intent);

    }

});

 

 

 

 

2.自己写线程下载文件

当然,你可能不想把下载文件放到默认路径下,或者想自己定义文件名等等,你都可以自己来写 一个线程来下载文件,实现示例代码如下:

核心代码

我们自己另外写一个下载的线程类:

DownLoadThread.java

/**
 * Created by Jay on 2015/9/14 0014.
 */
public class DownLoadThread implements Runnable {
 
    private String dlUrl;
 
    public DownLoadThread(String dlUrl) {
        this.dlUrl = dlUrl;
    }
 
    @Override
    public void run() {
        Log.e("HEHE", "开始下载~~~~~");
        InputStream in = null;
        FileOutputStream fout = null;
        try {
            URL httpUrl = new URL(dlUrl);
            HttpURLConnection conn = (HttpURLConnection) httpUrl.openConnection();
            conn.setDoInput(true);
            conn.setDoOutput(true);
            in = conn.getInputStream();
            File downloadFile, sdFile;
            if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
                Log.e("HEHE","SD卡可写");
                downloadFile = Environment.getExternalStorageDirectory();
                sdFile = new File(downloadFile, "csdn_client.apk");
                fout = new FileOutputStream(sdFile);
            }else{
                Log.e("HEHE","SD卡不存在或者不可读写");
            }
            byte[] buffer = new byte[1024];
            int len;
            while ((len = in.read(buffer)) != -1) {
                fout.write(buffer, 0, len);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fout != null) {
                try {
                    fout.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        Log.e("HEHE", "下载完毕~~~~");
    }
}

然后MainActivity.java中创建并启动该线程:

wView.setDownloadListener(new DownloadListener(){
               @Override
               public void onDownloadStart(String url, String userAgent, String contentDisposition, 
    String mimetype, long contentLength) {
            Log.e("HEHE","onDownloadStart被调用:下载链接:" + url);
            new Thread(new DownLoadThread(url)).start();
    }
});

 

 

Java中定义ColorDrawable:

ColorDrawable drawable = new ColorDrawable(0xffff2200);  
txtShow.setBackground(drawable);  

利用静态方法argb来设置颜色:

Android使用一个int类型的数据表示颜色值,通常是十六进制,即0x开头, 颜色值的定义是由透明度alpha和RGB(红绿蓝)三原色来定义的,以"#"开始,后面依次为:
透明度-红-绿-蓝;eg:#RGB#ARGB #RRGGBB #AARRGGBB
每个要素都由一个字节(8bit)来表示,所以取值范围为0~255,在xml中设置颜色可以忽略透明度, 但是如果你是在Java代码中的话就需要明确指出透明度的值了,省略的话表示完全透明,这个时候 就没有效果了哦~比如:0xFF0000虽然表示红色,但是如果直接这样写,什么的没有,而应该这样写: 0xFFFF0000,记Java代码设置颜色值,需要在前面添加上透明度~ 示例:(参数依次为:透明度,红色值,绿色值,蓝色值) txtShow.setBackgroundColor(Color.argb(0xff,0x00, 0x00, 0x00));

 

 

ShapeDrawable

形状的Drawable咯,定义基本的几何图形,如(矩形,圆形,线条等),根元素是<shape../> 节点比较多,相关的节点如下:

·        ① <shape>:

·        ~ visible:设置是否可见

·        ~ shape:形状,可选:rectangle(矩形,包括正方形),oval(椭圆,包括圆),line(线段),ring(环形)

·        ~ innerRadiusRatio:当shape为ring才有效,表示环内半径所占半径的比率,如果设置了innerRadius, 他会被忽略

·        ~ innerRadius:当shape为ring才有效,表示环的内半径的尺寸

·        ~ thicknessRatio:当shape为ring才有效,表环厚度占半径的比率

·        ~ thickness:当shape为ring才有效,表示环的厚度,即外半径与内半径的差

·        ~ useLevel:当shape为ring才有效,表示是否允许根据level来显示环的一部分

·        ②<size>:

·        ~ width:图形形状宽度

·        ~ height:图形形状高度

·        ③<gradient>:后面GradientDrawable再讲~

·        ④<solid>

·        ~ color:背景填充色,设置solid后会覆盖gradient设置的所有效果!!!!!!

·        ⑤<stroke>

·        ~ width:边框的宽度

·        ~ color:边框的颜色

·        ~ dashWidth:边框虚线段的长度

·        ~ dashGap:边框的虚线段的间距

·        ⑥<conner>

·        ~ radius:圆角半径,适用于上下左右四个角

·        ~ topLeftRadius,topRightRadius,BottomLeftRadius,tBottomRightRadius:依次是左上,右上,左下,右下的圆角值,按自己需要设置!

·        ⑦<padding>

·        left,top,right,bottm:依次是左上右下方向上的边距!

GradientDrawable

一个具有渐变区域的Drawable,可以实现线性渐变,发散渐变和平铺渐变效果 核心节点:<gradient/>,有如下可选属性:

·        startColor:渐变的起始颜色

·        centerColor:渐变的中间颜色

·        endColor:渐变的结束颜色

·        type:渐变类型,可选(linear,radial,sweep),线性渐变(可设置渐变角度),发散渐变(中间向四周发散),平铺渐变

·        centerX:渐变中间亚瑟的x坐标,取值范围为:0~1

·        centerY:渐变中间颜色的Y坐标,取值范围为:0~1

·        angle:只有linear类型的渐变才有效,表示渐变角度,必须为45的倍数哦

·        gradientRadius:只有radial和sweep类型的渐变才有效,radial必须设置,表示渐变效果的半径

·        useLevel:判断是否根据level绘制渐变效果

 

 

 

 

 

·        先在drawable下创建三个渐变xml文件:

·        (线性渐变)gradient_linear.xml:

·         <?xml version="1.0" encoding="utf-8"?>
·         <shape
·             xmlns:android="http://schemas.android.com/apk/res/android"
·             android:shape="oval" >
·             <gradient
·                 android:angle="90"
·                 android:centerColor="#FFEB82"
·                 android:endColor="#35B2DE"
·                 android:startColor="#DEACAB" />
·          
·             <stroke
·                 android:dashGap="5dip"
·                 android:dashWidth="4dip"
·                 android:width="3dip"
·                 android:color="#fff" />
·         </shape>

·        (发散渐变)gradient_radial.xml:

·         <?xml version="1.0" encoding="utf-8"?>
·         <shape xmlns:android="http://schemas.android.com/apk/res/android"
·             android:innerRadius="0dip"
·             android:shape="ring"
·             android:thickness="70dip"
·             android:useLevel="false" >
·          
·             <gradient
·                 android:centerColor="#FFEB82"
·                 android:endColor="#35B2DE"
·                 android:gradientRadius="70"
·                 android:startColor="#DEACAB"
·                 android:type="radial"
·                 android:useLevel="false" />
·          
·         </shape> 

·        (平铺渐变)gradient_sweep.xml:

·         <?xml version="1.0" encoding="utf-8"?>
·         <shape xmlns:android="http://schemas.android.com/apk/res/android"
·             android:innerRadiusRatio="8"
·             android:shape="ring"
·             android:thicknessRatio="3"
·             android:useLevel="false" >
·          
·             <gradient
·                 android:centerColor="#FFEB82"
·                 android:endColor="#35B2DE"
·                 android:startColor="#DEACAB"
·                 android:type="sweep"
·                 android:useLevel="false" />
·          
·         </shape> 

 

 

 

InsetDrawable

表示把一个Drawable嵌入到另外一个Drawable的内部,并且在内部留一些间距, 类似与Drawable的padding属性,但padding表示的是Drawable的内容与Drawable本身的边距! 而InsetDrawable表示的是两个Drawable与容器之间的边距,当控件需要的背景比实际的边框 小的时候,比较适合使用InsetDrawable,比如使用这个可以解决我们自定义Dialog与屏幕之间 的一个间距问题,相信做过的朋友都知道,即使我们设置了layout_margin的话也是没用的,这个 时候就可以用到这个InsetDrawable了!只需为InsetDrawable设置一个insetXxx设置不同 方向的边距,然后为设置为Dialog的背景即可!

相关属性如下:

·        1.drawable:引用的Drawable,如果为空,必须有一个Drawable类型的子节点!

·        2.visible:设置Drawable是否额空间

·        3.insetLeft,insetRight,insetTop,insetBottm:设置左右上下的边距

①XML中使用:

<?xmlversion="1.0" encoding="utf-8"?> 

<inset xmlns:android="http://schemas.android.com/apk/res/android" 

   android:drawable="@drawable/test1" 

    android:insetBottom="10dp" 

    android:insetLeft="10dp" 

    android:insetRight="10dp" 

    android:insetTop="10dp" />

在Java代码中使用

InsetDrawable insetDrawable =new InsetDrawable(getResources() 

        .getDrawable(R.drawable.test1), 10, 10,10, 10);

 

 

 

ClipDrawable

Clip可以译为剪的意思,我们可以把ClipDrawable理解为从位图上剪下一个部分; Android中的进度条就是使用ClipDrawable来实现的,他根据设置level的值来决定剪切 区域的大小,根节点是<clip>

相关属性如下

·        clipOrietntion:设置剪切的方向,可以设置水平和竖直2个方向

·        gravity:从那个位置开始裁剪

·        drawable:引用的drawable资源,为空的话需要有一个Drawable类型的子节点 ps:这个Drawable类型的子节点:就是在<clip里>加上这样的语句: 这样...

使用示例

核心:通过代码修改ClipDrawable的level的值!Level的值是0~10000!

运行效果图

代码实现

①定义一个ClipDrawable的资源xml:

<?xmlversion="1.0" encoding="utf-8"?>

<clipxmlns:android="http://schemas.android.com/apk/res/android"

   android:clipOrientation="horizontal"

   android:drawable="@mipmap/ic_bg_meizi"

    android:gravity="left" />

②在activity_main主布局文件中设置一个ImageView,将src设置为clipDrawable! 记住是src哦,如果你写成了blackground的话可是会报空指针的哦!!!!

<LinearLayoutxmlns: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">

 

    <ImageView

        android:id="@+id/img_show"

       android:layout_width="match_parent"

       android:layout_height="match_parent"

       android:src="@drawable/clip_bg" />

 

</LinearLayout> 

③MainActivity.java通过setLevel设置截取区域大小:

public class MainActivityextends AppCompatActivity {

 

    private ImageView img_show;

    private ClipDrawable cd;

    private Handler handler = new Handler() {

        @Override

        public void handleMessage(Message msg){

            if (msg.what == 0x123) {

                cd.setLevel(cd.getLevel() +500);

            }

        }

    };

 

    @Override

    protected void onCreate(BundlesavedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        img_show = (ImageView)findViewById(R.id.img_show);

        // 核心实现代码

        cd = (ClipDrawable)img_show.getDrawable();

        final Timer timer = new Timer();

        timer.schedule(new TimerTask() {

            @Override

            public void run() {

               handler.sendEmptyMessage(0x123);

                if (cd.getLevel() >= 10000){

                    timer.cancel();

                }

            }

        }, 0, 300);

    }

}

 

 

获取Bitmap位图

从资源中获取位图的方式有两种:通过BitmapDrawable或者BitmapFactory,下面演示下: 我们首先得获得这个

BitmapDrawable方法

你可以创建一个构造一个BitmapDrawable对象,比如通过流构建BitmapDrawable:

BitmapDrawable bmpMeizi = newBitmapDrawable(getAssets().open("pic_meizi.jpg"));

Bitmap mBitmap =bmpMeizi.getBitmap();

img_bg.setImageBitmap(mBitmap);

BitmapFactory方法

都是静态方法,直接调,可以通过资源ID、路径、文件、数据流等方式来获取位图!

//通过资源ID

private BitmapgetBitmapFromResource(Resources res, int resId) {

      return BitmapFactory.decodeResource(res,resId);

}

 

//文件

private BitmapgetBitmapFromFile(String pathName) {

      return BitmapFactory.decodeFile(pathName);

}

 

//字节数组

public BitmapBytes2Bimap(byte[] b) {

    if (b.length != 0) {

        return BitmapFactory.decodeByteArray(b,0, b.length);

    } else {

        return null;

    }

}

 

//输入流

private BitmapgetBitmapFromStream(InputStream inputStream) {

      returnBitmapFactory.decodeStream(inputStream);

}


获取Bitmap的相关信息:

这个,只要我们获取了Bitmap对象,就可以调用相关方法来获取对应的参数了,getByteCount获得大小, getHeight和getWidth这些~这里就不写了,自己查文档!

抠图片上的某一角下来

有时,可能你想把图片上的某一角扣下来,直接通过Bitmap的createBitmap()扣下来即可 参数依次为:处理的bitmap对象,起始x,y坐标,以及截取的宽高

Bitmap bitmap1 = BitmapFactory.decodeResource(getResources(), R.mipmap.pic_meizi);
Bitmap bitmap2 = Bitmap.createBitmap(bitmap1,100,100,200,200);
img_bg = (ImageView) findViewById(R.id.img_bg);
img_bg.setImageBitmap(bitmap2);

 

 

对Bitmap进行缩放

我们这里不用Matrix来对Bitmap,而是直接使用Bitmap给我们提供的createScaledBitmap来实现, 参数依次是:处理的bitmap对象,缩放后的宽高,

BlurMaskFilter(模糊效果)

BlurMaskFilter(10f,BlurMaskFilter.Blur.NORMAL);

我们可以控制的就是这两个参数:

第一个参数:指定模糊边缘的半径;

第二个参数:指定模糊的风格,可选值有:

  • BlurMaskFilter.Blur.NORMAL:内外模糊
  • BlurMaskFilter.Blur.OUTER:外部模糊
  • BlurMaskFilter.Blur.INNER:内部模糊
  • BlurMaskFilter.Blur.SOLID:内部加粗,外部模糊

EmbossMaskFilter(浮雕效果)

EmbossMaskFilter(float[]direction, float ambient, float specular, float blurRadius) 参数依次是:

direction:浮点型数组,用于控制x,y,z轴的光源方向

ambient:设置环境光亮度,0到1之间

specular:镜面反射系数

blurRadius:模糊半径

注意事项

在使用MaskFilter的时候要注意,当我们的targetSdkVersion >=14的时候,MaskFilter 就不会起效果了,这是因为Android在API 14以上版本都是默认开启硬件加速的,这样充分 利用GPU的特性,使得绘画更加平滑,但是会多消耗一些内存!好吧,我们把硬件加速关了就好,可以在不同级别下打开或者关闭硬件加速,一般是关闭~

·        Application:在配置文件的application节点添加:android:hardwareAccelerated="true"

·        Activity:在配置文件的activity节点添加android:hardwareAccelerated="false"

·        View:可以获得View对象后调用,或者直接在View的onDraw()方法里设置:view.setLayerType(View.LAYER_TYPE_HARDWARE, null);

 

 

AvoidXfermode

嗯,和前面学的MaskFilter的两个子类一样,不支持硬件加速,所以如果是API 14以上的版本, 需要关闭硬件加速才会有效果!怎么关自己看上一节哈~

PS:需要在AndroidManifest.xml中的appliction节点添加关闭硬件加速: android:hardwareAccelerated="false"

我们来看看他给我们提供的构造方法!官方API文档:AvoidXfermode

参数有三个,依次是:

opColor:一个十六进制的带透明度的颜色值,比如0x00C4C4;

tolerance:容差值,如果你学过PS可能用过魔棒工具,就是设置选取颜色值的范围,比如 容差为0,你选的是纯黑的小点,当容差调为40的时候,范围已经扩大到大块黑色这样!如果 还不是很明白,等下我们写写代码就知道了!

mode:AvoidXfermode模式,有两种:TARGETAVOID


模式1:AvoidXfermode.Mode.TARGET

该模式会判断画布上是否有与我们设置颜色值不一样的颜色,如果有的话,会把这些区域 染上一层画笔定义的颜色,其他地方不染色!下面我们写代码演示下,顺便让大家感觉下这个容差值!

模式2:AvoidXfermode.Mode.AVOID

和上面的TARGET模式相反,上面是颜色一样才改变颜色,这里是颜色不一样反而改变颜色, 而容差值同样带来相反的结果,容差值为0时,只有当图片中的像素颜色值与设置的颜色值完全不一样 的时候才会被染色,而当容差值达到最大值255的时候,稍微有一点颜色不一样就会被染色! 我们只需简单的修改上面的例子就可以了,同一是修改下构造AvoidXfermode的内容! 我们改成下面这句:

avoidXfermode = new AvoidXfermode(0XFFD9E5F3,230, AvoidXfermode.Mode.AVOID);

 

 

构造方法详解


1)BitmapShader(图像渲染)

BitmapShader(Bitmapbitmap, Shader.TileMode tileX, Shader.TileMode tileY)

使用一张位图作为纹理来对某一区域进行填充,参数依次:

  • bitmap:用来作为填充的位图;
  • tileX:X轴方向上位图的衔接形式;
  • tileY:Y轴方向上位图的衔接形式;

而这个Shader.TileMode有三种:

  • CLAMP就是如果渲染器超出原始边界范围,则会复制边缘颜色对超出范围的区域进行着色
  • REPEAT则是平铺形式重复渲染
  • MIRROR则是在横向和纵向上以镜像的方式重复渲染位图。

2)ComposeShader(混合渲染)

ComposeShader(ShadershaderA, Shader shaderB, PorterDuff.Mode mode)

渲染效果的叠加,看到PorterDuff就知道什么了吧?比如将BitmapShader与LinearGradient的混合渲染 效果等。参数依次:

  • shaderA:第一种渲染效果
  • shaderB:第二种渲染效果
  • mode:两种渲染效果的叠加模式

3)LinearGradient(线性渲染)

LinearGradient(floatx0, float y0, float x1, float y1, int[] colors, float[] positions,Shader.TileMode tile);

实现某一区域内颜色的线性渐变效果,参数依次是:

  • x0:渐变的起始点x坐标
  • y0:渐变的起始点y坐标
  • x1:渐变的终点x坐标
  • y1:渐变的终点y坐标
  • colors:渐变的颜色数组
  • positions:颜色数组的相对位置
  • tile:平铺方式

4)RadialGradient(环形渲染)

publicRadialGradient (float x, float y, float radius, int[] colors, float[]positions, Shader.TileMode tile);

实现某一区域内颜色的环形渐变效果,参数依次是:

  • x:环形的圆心x坐标
  • y:环形的圆心y坐标
  • radius:环形的半径
  • colors:环形渐变的颜色数组
  • positions:指定颜色数组的相对位置
  • tile:平铺方式

5)SweepGradient(梯度渲染)

publicSweepGradient (float cx, float cy, int[] colors, float[] positions)

扫描渲染,就是以某个点位中心旋转一周所形成的效果!参数依次是:

  • cx:扫描的中心x坐标
  • cy:扫描的中心y坐标
  • colors:梯度渐变的颜色数组
  • positions:指定颜色数组的相对位置

 

 

Matrix中的几个常用的变换方法

·        setTranslate(float dx, float dy):控制Matrix进行平移

·        setRotate(float degrees, float px, float py):旋转,参数依次是:旋转角度,轴心(x,y)

·        setScale(float sx, float sy, float px, float py):缩放, 参数依次是:X,Y轴上的缩放比例;缩放的轴心

·        setSkew(float kx, float ky):倾斜(扭曲),参数依次是:X,Y轴上的缩放比例

 

 

translate(平移)

方法translate(float dx, floatdy)

解析:平移,将画布的坐标原点向左右方向移动x,向上下方向移动y,canvas默认位置在(0,0)

参数:dx为水平方向的移动距离,dy为垂直方向的移动距离

使用示例

for(int i=0; i < 5; i++) {

   canvas.drawCircle(50, 50, 50, mPaint);

   canvas.translate(100, 100);

}

 

rotate(旋转)

方法rotate(float degrees) / rotate(floatdegrees, float px, float py)

解析:围绕坐标原点旋转degrees度,值为正顺时针

参数:degrees为旋转角度,px和py为指定旋转的中心点坐标(px,py)

使用示例

Rect rect = new Rect(50,0,150,50);

canvas.translate(200, 200);

for(int i = 0; i < 36;i++){

   canvas.rotate(10);

   canvas.drawRect(rect, mPaint);

}

 

scale(缩放)

方法scale(float sx, float sy)/ scale(float sx, float sy, float px, float py)

解析:对画布进行缩放

参数:sx为水平方向缩放比例,sy为竖直方向的缩放比例,px和py我也不知道,小数为缩小整数为放大

使用示例

canvas.drawBitmap(bmp,0,0,mPaint);

canvas.scale(0.8f, 0.8f);

canvas.drawBitmap(bmp, 0, 0, mPaint);

canvas.scale(0.8f, 0.8f);

canvas.drawBitmap(bmp,0,0,mPaint);

 

skew(倾斜)

方法skew(float sx, float sy)

解析:倾斜,也可以译作斜切,扭曲

参数:sx为x轴方向上倾斜的对应角度,sy为y轴方向上倾斜的对应角度,两个值都是tan值哦! 都是tan值!都是tan值!比如要在x轴方向上倾斜60度,那么小数值对应:tan60 = 根号3 = 1.732!

使用示例

canvas.drawBitmap(bmp,0,0,mPaint);

canvas.translate(200, 200);

canvas.skew(0.2f,-0.8f);

canvas.drawBitmap(bmp,0,0,mPaint);

 

 

Canvas图层的概念以及save()和restore()详解

我们一般喜欢称呼Canvas为画布,童鞋们一直觉得Canvas就是一张简单的画纸,那么我想问下多层的动画是怎么用canvas来完成的?上面那个translate平移的例子,为什么 drawCircle(50, 50, 50, mPaint); 参考坐标一直是(50,50)那为何会出现这样的效果?有疑惑的童鞋可能是一直将屏幕的概念与Canvas的概念混淆了,下面我们来还原下 调用translate的案发现场:

如图,是画布坐标原点的每次分别在x,y轴上移动100;那么假如我们要重新回到(0,0) 点处绘制新的图形呢?怎么破,translate(-100,-100)的慢慢地平移回去?不会真的这么纠结吧...

好吧,不卖关子了,我们可以在做平移变换之前将当前canvas的状态进行保存,其实Canvas为 我们提供了图层(Layer)的支持,而这些Layer(图层)是按"栈结构"来进行管理的

当我们调用save()方法,会保存当前Canvas的状态然后作为一个Layer(图层),添加到Canvas栈中,另外,这个Layer(图层)不是一个具体的类,就是一个概念性的东西而已!

而当我们调用restore()方法的时候,会恢复之前Canvas的状态,而此时Canvas的图层栈 会弹出栈顶的那个Layer,后继的Layer来到栈顶,此时的Canvas回复到此栈顶时保存的Canvas状态!

简单说就是:save()往栈压入一个Layer,restore()弹出栈顶的一个Layer,这个Layer代表Canvas的状态!也就是说可以save()多次,也可以restore()多次,但是restore的调用次数不能大于save 否则会引发错误!这是网上大部分的说法,不过实际测试中并没有出现这样的问题,即使我restore的 次数多于save,也没有出现错误~目测是系统改了,等下测给大家看~ 来来来,写个例子验证下save和restore的作用!

写个例子

例子代码

canvas.save();  //保存当前canvas的状态

 

canvas.translate(100, 100);

canvas.drawCircle(50, 50, 50, mPaint);

 

canvas.restore(); //恢复保存的Canvas的状态

canvas.drawCircle(50, 50, 50, mPaint);

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值