View体系与自定义View 【1】

一.View

View是庞大的,对于一个APP来说,与用户的交互、将内容展现给用户的部分是重要而且必要的,View也是微小的,屏幕上的一个小部分,都可能是一个View,而我们UI学习的第一步,也是从最简单的Textview,Button开始的,到后来,我们可以试着去写一些自定义的View来实现效果,这就是需要我们很好的掌握View的机制和工作流程。

二.ViewGroup

平时我们用的布局空间XXXLayout是继承自ViewGroup,那么这个ViewGroup可以理解为View的组合,他可以包含很多ViewGroup和View,这也是布局嵌套的本质。

三.坐标系

Android系统中有两种坐标系,Android坐标系和View坐标系。

1.Android坐标系

屏幕左上角为原点,原点向右为X正方向,向下是Y正方向

2.View坐标系

View的坐标系与Android的坐标系并不冲突,它们是共同存在的,它可以用来更好的控制View


那么从图中我们可以看到计算一个View的宽和高的方法

  int width = button.getRight() - button.getLeft();
  int height = button.getBottom() - button.getTop();

注意这个代码不能在onCreate里面写,因为当时View还没有做好初始化,是测量不到宽高的,其中一个方法如下


    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        int width = button.getRight() - button.getLeft();
        int height = button.getBottom() - button.getTop();
    }

onWindowFocusChanged含义就是view已经初始化完毕,这个时候去获取宽高就没问题了,但是要注意的是此方法会被调用很多次,当Activity的窗口失去或者得到焦点都会调用一次,也就是Activity onResume或onPause时都会调用。
那么这样做的思路是对的,不过不必要这么麻烦了,系统已经为我们做好这步工作了。

我们可以直接用getWidth()和getHeight()来获取view宽高,得到的效果是一样的,我们可以直接看一下SDK源码。

AS查看源代码的方法:http://blog.csdn.net/glc_csdn/article/details/53993903

 /**
     * Return the width of the your view.
     *
     * @return The width of your view, in pixels.
     */
    @ViewDebug.ExportedProperty(category = "layout")
    public final int getWidth() {
        return mRight - mLeft;
    }

    /**
     * Return the height of your view.
     *
     * @return The height of your view, in pixels.
     */
    @ViewDebug.ExportedProperty(category = "layout")
    public final int getHeight() {
        return mBottom - mTop;
    }

同时我们看到还有好多方法
getTop() : 获取View顶部到父布局顶距离
getLeft() : 获取View左部到父布局左距离
getRight() : 获取View右部到父布局左距离
getBottom() : 获取View底部到父布局底距离

MotionEvent是为我们触摸点提供的方法,
getX():点击事件距离控件左边的距离
getY():点击事件距离控件顶边的距离
getRawX():点击事件距离父布局左边的距离
getRawY():点击事件距离父布局顶边的距离

View滑动

滑动实现思路是:当点击事件传到View后,系统记录触摸点坐标,手指移动系统记录移动后坐标并计算偏移量,通过偏移量来修改View坐标。
下面是几种View滑动方式

1.layout() 方法

我们来实现一个view滑动的效果
实现自定义View并在xml里面引用它

public class CustomView extends View {
    private int lastX;
    private int lastY;
    public CustomView(Context context) {
        super(context);
    }

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

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

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public CustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    //触摸事件
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //获取事件的横纵坐标(相对于View)
        int x = (int) event.getX();
        int y = (int) event.getY();

        //事件的监听
        switch (event.getAction()){
            //按下的时候记录触摸点的值
            case MotionEvent.ACTION_DOWN:
                lastX = x;
                lastY = y;
                break;
            //移动过程中不断重绘
            case MotionEvent.ACTION_MOVE:
                //计算偏移量
                int offsetX = x - lastX;
                int offsetY = y - lastY;
                //重新布局
                layout(getLeft()+offsetX,getTop()+offsetY,getRight()+offsetX,getBottom()+offsetY);
                break;
        }

        return true;
    }
}
  <com.surine.viewlearn.CustomView
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:background="@color/colorPrimary"
        />

具体效果图,这里我放了4个自定义的view里面


Screenshot_2017-09-27-21-52-33-179_com.surine.vie.png
2.offsetLeftAndRight()与offsetTopAndBottom()

这两个方法的效果是和layout一样的,但是他们可以直接使用偏移量

  //偏移操作
  offsetLeftAndRight(offsetX);
 offsetTopAndBottom(offsetY);
3.LayoutParams(布局参数)

这个东西在调整view的宽高度,margin等中经常用到,那么我们换个思维,移动也就是在改变view的margin(对于父布局),具体的代码:

 LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) getLayoutParams();
                layoutParams.leftMargin = getLeft() + offsetX;
                layoutParams.topMargin = getLeft() + offsetY;
                setLayoutParams(layoutParams);

这里用了LinearLayout.LayoutParams,这是跟你的父布局的类型来决定,所以相对其他方法比较麻烦一点。

4.Animation

一个不是属于触摸移动的方式,使用动画,这就相对好理解一些,给view设置一个位移的动画,实现思路如下。

创建动画文件(res/anim/translate.xml)

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true"
>
    <translate
        android:fromXDelta="0"
        android:toXDelta="300"
        android:duration = "1000"
        />
</set>

启动动画

 custom_view = findViewById(R.id.custom_view);
        custom_view.setAnimation(AnimationUtils.loadAnimation(this,R.anim.translate));

当然我们用的是普通的动画,改变view的显示但并没有改变view的位置参数,所以对于点击事件来说不是很友好,那么这个问题在Android3以后的版本得到了解决,那就是属性动画。具体在后面的文章哦。

5.scrollTo与scrollBy

scrollTo是移动到某个坐标点,而scrollby是移动增量,那么他们的源码如下。

 public void scrollBy(int x, int y) {
        scrollTo(mScrollX + x, mScrollY + y);
    }

可以看到scrollby是调用了scrollTo方法的,传的参数是一个当前值+增量

public void scrollTo(int x, int y) {
        if (mScrollX != x || mScrollY != y) {
            int oldX = mScrollX;
            int oldY = mScrollY;
            mScrollX = x;
            mScrollY = y;
            invalidateParentCaches();
            onScrollChanged(mScrollX, mScrollY, oldX, oldY);
            if (!awakenScrollBars()) {
                postInvalidateOnAnimation();
            }
        }
    }

这里是scrollTo的方法体,mScrollX和mScrollY用于描述View的内容在水平方向或垂直方向滚动的距离。 那么在这里注意一下View的内容仅仅是指其中的东西,而不是View全部,例如textview的文字

那么我们要写具体的代码就是下面的这一行(在 case MotionEvent.ACTION_MOVE:标签内写)

 ((View)getParent()).scrollBy(-offsetX,-offsetY);

这里设置负数是因为视图与我们坐标轴的移动方向是相反的,可以想想中学实验显微镜的波片的移动和视野内的显示的例子。

View是Android中主要的一部分,掌握了View的基本操作才能更好的进阶!

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

推荐阅读更多精彩内容