您的位置:首页 > 移动开发 > Android开发

Android 知识点

2016-02-24 17:24 477 查看
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);
 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: