Android 自定義View

一、構(gòu)造方法

    public MyView(Context context) {  //在代碼中直接創(chuàng)建對(duì)象
        super(context);
    }

    public MyView(Context context, @Nullable AttributeSet attrs) { //默認(rèn)調(diào)用
        super(context, attrs);
    }

    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { //手動(dòng)顯式調(diào)用
        super(context, attrs, defStyleAttr);
    }

    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {  //手動(dòng)顯式調(diào)用
        super(context, attrs, defStyleAttr, defStyleRes);
    }
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.BottomView);
array.recycle();
參數(shù)解析:
  • context:上下文,View當(dāng)前處于的環(huán)境。
  • attrs:View的屬性參數(shù),一般在布局文件中設(shè)置。
  • defStyleAttr:attrs.xml文件中的attribute,屬于自定義屬性。
  • defStyleRes:styles.xml文件中的style,只有當(dāng)defStyleAttr沒(méi)有起作用,才會(huì)使用到這個(gè)值。
    //自定義屬性文件,attr.xml
    <declare-styleable name="SlideMenu">
        <attr name="rightPadding" format="dimension"/>
    </declare-styleable>
一個(gè)屬性最終的取值,有一個(gè)順序,這個(gè)順序優(yōu)先級(jí)從高到低依次是:

1.直接在XML文件中定義的 ==》布局文件。
2.在XML文件中通過(guò)style這個(gè)屬性定義的 ==》在布局中使用自定義屬性樣式。
3.通過(guò)defStyleAttr定義的 ==》在View的構(gòu)造方法中使用自定義屬性樣式。
4.通過(guò)defStyleRes定義的 ==》在View的構(gòu)造方法中使用自定義樣式。
5.直接在當(dāng)然工程的theme主題下定義的 ==》AndroidManifest.xml中設(shè)置。

二、測(cè)量流程

 @Override -> 使用默認(rèn)的測(cè)量方法,由父類測(cè)量
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int measuredWidth =getMeasuredWidth();
        int measuredHeight =getMeasuredHeight();
        //測(cè)量已經(jīng)完成,可以獲取測(cè)量的參數(shù)值
    }
 @Override -> 覆寫(xiě)默認(rèn)的測(cè)量方法,自定義測(cè)量規(guī)則
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //測(cè)量模式
        int widthMode =MeasureSpec.getMode(widthMeasureSpec);
        int heightMode =MeasureSpec.getMode(heightMeasureSpec);
        //測(cè)量寬高
        int width =MeasureSpec.getSize(widthMeasureSpec);
        int height=MeasureSpec.getSize(heightMeasureSpec);
        setMeasuredDimension(width,height);
    }
測(cè)量模式解析:
  • MeasureSpec.AT_MOST:父容器指定最大的空間,WRAP_CONTENT屬性
  • MeasureSpec.EXACTLY:父容器指定精確的大小空間,MATCH_PARENT 或者 一個(gè)精確值
  • MeasureSpec.UNSPECIFIED:父容器未指定空間的大小,父容器是ScrollerView等可滑動(dòng)控件
    寬高解析:
  • getWidth()和getHeight():View的最終大小,測(cè)量方法完成后可以得到具體的值
  • getMeasureWidth()和getMeasureHeight():View的測(cè)量大小,測(cè)量完成后可以得到具體的值
  • 寬的計(jì)算:控件的右邊到屏幕的左邊的距離 --- 控件的左邊到屏幕左邊的距離,即 right - left
  • 高的計(jì)算:控件的下邊到屏幕的上邊的距離 --- 控件的上邊到屏幕上邊的距離,即 bottom - top
  • 屬性詳解:top,控件頂部到屏幕頂部的距離。bottom,控件底部到屏幕頂部的距離。left,控件左邊到屏幕左邊的距離。right,控件右邊到屏幕左邊的距離。
//當(dāng)View的尺寸發(fā)生變化時(shí)會(huì)觸發(fā),如onMeasure完成后
 @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        //初始化一些有關(guān)尺寸的成員變量
    }
//自定義ViewGroup,還要測(cè)量子View的大小
measureChild(child, widthMeasureSpec, heightMeasureSpec);
  • 設(shè)置控件自適應(yīng)屏幕時(shí)的大小(在某些特殊情況,View的AT_MOST模式可以同時(shí)對(duì)應(yīng)wrap_content和match_parent兩種布局參數(shù),所以通過(guò)測(cè)量模式來(lái)判斷控件所設(shè)置的屬性wrap_content和match_parent是不準(zhǔn)確的)
        if (getLayoutParams().width == ViewGroup.LayoutParams.WRAP_CONTENT && getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT) {
            setMeasuredDimension(mWidth, mHeight);
        } else if (getLayoutParams().width == ViewGroup.LayoutParams.WRAP_CONTENT) {
            setMeasuredDimension(mWidth, heightSize);
        } else if (getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT) {
            setMeasuredDimension(widthSize, mHeight);
        }
onMeasure、Measure、measureChild、measureChildren 的區(qū)別

1、onMeasure 測(cè)量自身,自定義View時(shí)重寫(xiě),定義控件的寬高,常在自定義的View中使用
2、Measure 測(cè)量自身,方法不可重寫(xiě),內(nèi)部調(diào)用onMeasure方法,常在自定義的ViewGroup中使用
3、measureChild 測(cè)量某個(gè)子View,內(nèi)部調(diào)用Measure方法,常在自定義的ViewGroup中使用
4、measureChildren 測(cè)量所有子View,內(nèi)部調(diào)用measureChild方法,常在自定義的ViewGroup中使用

創(chuàng)建新的測(cè)量參數(shù)

在自定義View的開(kāi)發(fā)中,我們重寫(xiě)測(cè)量方法,方法里的傳參(widthMeasureSpec,heightMeasureSpec)都是由父類提供的,在自定義ViewGroup的開(kāi)發(fā)中,我們可以根據(jù)當(dāng)前布局的測(cè)量參數(shù),為布局內(nèi)的子控件創(chuàng)建新的測(cè)量參數(shù),來(lái)控制子View在布局的顯示大小

            int widthSize = MeasureSpec.getSize(widthMeasureSpec);
            int widthMode = MeasureSpec.getMode(widthMeasureSpec);
            int childWidthSpec = MeasureSpec.makeMeasureSpec(widthSize,widthMode);

三、布局流程

ViewGroup中的方法,設(shè)置子View的布局參數(shù)和顯示位置
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) { 
        if (changed) {
            layoutArcButton();

            int count = getChildCount();
            for (int i = 0; i < count - 1; i++) {
                View child = getChildAt(i + 1);
                child.setVisibility(View.GONE);
                //為什么-2,因?yàn)橹鞑藛我彩瞧渲幸粋€(gè)子控件
                int left = (int) (mRadius * Math.sin(Math.PI / 2 / (count - 2) * i));
                int top = (int) (mRadius * Math.cos(Math.PI / 2 / (count - 2) * i));

                int width = child.getMeasuredWidth();
                int height = child.getMeasuredHeight();

                //菜單在左下或者右下角
                if (mPosition == Position.LEFT_BOTTOM || mPosition == Position.RIGHT_BOTTOM) {
                    top = getMeasuredHeight() - height - top;
                }

                if (mPosition == Position.RIGHT_BOTTOM || mPosition == Position.RIGHT_TOP) {
                    left = getMeasuredWidth() - width - left;
                }
                //布局子View
                child.layout(left, top, left + width, top + height);
            }
        }
    }
View的生命周期方法,在Activity.onCreate()中會(huì)加載布局,在布局文件完成加載后會(huì)觸發(fā)該方法,常用于操縱子View,設(shè)置子View的布局參數(shù),如果View的創(chuàng)建不通過(guò)布局文件加載,則該方法不會(huì)被觸發(fā),例如調(diào)用View的一個(gè)參數(shù)的構(gòu)造方法
    @Override
    protected void onFinishInflate() { -> Activity onCreate 執(zhí)行完觸發(fā)
        super.onFinishInflate();
        //獲取子控件個(gè)數(shù)
        int count = getChildCount();
        if (count == 0) return;

        for (int i = 0; i < count; i++) {
            View view = getChildAt(i);
            LinearLayout.LayoutParams Lp = (LayoutParams) view.getLayoutParams();
            Lp.weight = 0;
            Lp.width = getScreenWidth() / mTabVisibleCount;
            view.setLayoutParams(Lp);
        }
    }
View的生命周期方法,在Activity.onResume()執(zhí)行后,View被加載到窗口時(shí)觸發(fā)該方法
    @Override
    protected void onAttachedToWindow() { -> Activity onResume 執(zhí)行完觸發(fā)
        super.onAttachedToWindow();
    }
View的生命周期方法,當(dāng)View從Window中被移除時(shí)觸發(fā)該方法,常見(jiàn)于viewGroup.removeView(view)或者當(dāng)前View所依賴的Activity被銷毀了
    @Override
    protected void onDetachedFromWindow() { -> View 移出窗口時(shí)觸發(fā)
        super.onDetachedFromWindow();
    }
自定義View的布局類型(線性、相對(duì)、流式等)
    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new MarginLayoutParams(getContext(), attrs);
    }
layout()、onLayout()、requestLayout()的區(qū)別

1、layout:指定View新的顯示位置,用法:view.layout(left,top,right,bottom);
2、onLayout:設(shè)置View的顯示位置,用法:重寫(xiě)該方法,定義View的顯示規(guī)則
3、requestLayout:強(qiáng)制View重新布局,用法:view.requestLayout();

注意:View的生命周期方法均在Activity.onResume()方法后執(zhí)行,所以在此之前,是獲取不到View的屬性的,比如在Activity.onCreate()中獲取View的寬高,盡管View已經(jīng)被創(chuàng)建,但得到View的寬高均為0,因?yàn)閂iew的生命周期方法未得到執(zhí)行,View還未經(jīng)過(guò)測(cè)量,所有屬性均是默認(rèn)值
View 生命周期方法執(zhí)行的先后順序

onFinishInflate -> onAttachedToWindow -> onMeasure -> onSizeChanged -> onLayout -> onDraw -> onDetachedFromWindow

四、繪制流程

繪制方法
    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawARGB(255,255,255,255);
    }
刷新界面,重新繪制
    private void invalidateView() {
        if (Looper.getMainLooper() == Looper.myLooper()) { //UI線程
            invalidate();
        } else { //非UI線程
            postInvalidate();
        }
    }
ViewGroup中的方法,用于繪制子控件
    @Override
    protected void dispatchDraw(Canvas canvas) {   
        canvas.save();
        canvas.translate(mInitTranslationX + mTranslationX, getHeight() + 2);
        canvas.drawPath(mPath, mPaint);
        canvas.restore();
        super.dispatchDraw(canvas);
    }

五、坐標(biāo)系

  • View自身的坐標(biāo)
  • getTop():獲取View自身頂邊到其父布局頂邊的距離
  • getLeft():獲取View自身左邊到其父布局左邊的距離
  • getRight():獲取View自身右邊到其父布局左邊的距離
  • getBottom():獲取View自身底邊到其父布局頂邊的距離
  • MotionEvent提供的方法
  • getX():獲取點(diǎn)擊事件距離控件左邊的距離,即視圖坐標(biāo)
  • getY():獲取點(diǎn)擊事件距離控件頂邊的距離,即視圖坐標(biāo)
  • getRawX():獲取點(diǎn)擊事件距離屏幕左邊的距離,即絕對(duì)坐標(biāo)
  • getRawY():獲取點(diǎn)擊事件距離屏幕左邊的距離,即絕對(duì)坐標(biāo)

六、View的滑動(dòng)

  • layout(left,top,right,bottom); View的坐標(biāo)點(diǎn)
  • offsetLeftAndRight(offsetX) 和 offsetTopAndBottom(offsetY); View的偏移量
  • MarginLayoutParams.leftMargin ,設(shè)置View的邊距改變View的位置
  • scrollTo(x,y) 和 scrollBy(x,y); 絕對(duì)位移和相對(duì)位移,瞬間完成
  • Scroller , 帶有過(guò)渡動(dòng)畫(huà)的滑動(dòng),擁有良好的用戶體驗(yàn)
public class CustomView extends View {
    private Scroller mScroller;
   
    public CustomView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        mScroller = new Scroller(context);
    }
    
    //系統(tǒng)會(huì)在繪制View的時(shí)候在draw中調(diào)用該方法
    @Override
    public void computeScroll() {
        super.computeScroll();
        if(mScroller.computeScrollOffset()){
            ((View)getParent()).scrollTo(mScroller.getCurrX(),mScroller.getCurrY());
            invalidate();
        }
    }
    
    public void smoothScrollTo(int destX,int destY){
        int scrollX =getScrollX();
        int delta = destX- scrollX;
        mScroller.startScroll(scrollX,0,delta,0,2000);
        invalidate();
    }
}
  • getScrollX() 和 getScrollY() ,View的左上角的點(diǎn)到View的父視圖左上角的點(diǎn)之間的X軸方向和Y軸方向的值

七、VelocityTracker

    //速度跟蹤器
    private VelocityTracker mVelocityTracker;
    //初始化滑動(dòng)速度跟蹤類
    mVelocityTracker = VelocityTracker.obtain();
    //計(jì)算一秒內(nèi)的滑動(dòng)速度
    mVelocityTracker.computeCurrentVelocity(1000);
    //獲取X方向的滑動(dòng)速度
    mVelocityTracker.getXVelocity();
    //獲取Y方向的滑動(dòng)速度
    mVelocityTracker.getYVelocity();
   
    @Override  //回收資源
    protected void onDetachedFromWindow() {
        mVelocityTracker.recycle();
        super.onDetachedFromWindow();
    }

八、事件分發(fā)機(jī)制

Android的事件分發(fā)可以理解為向下分發(fā),向上回傳,類似V字型,V字的左邊是事件進(jìn)行向下分發(fā),如果途中沒(méi)有進(jìn)行事件的分發(fā)攔截,則事件傳遞到最底層的View,即是最接近屏幕的View。V字的右邊是事件的回傳,如果中途沒(méi)有進(jìn)行事件的消費(fèi),則事件傳遞到最頂層的View,直至消失。

    @Override //事件分發(fā),默認(rèn)false
    public boolean dispatchTouchEvent(MotionEvent ev) {
        return super.dispatchTouchEvent(ev);
    }

    @Override //事件攔截,默認(rèn)false
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return super.onInterceptTouchEvent(ev);
    }

    @Override //事件消費(fèi),默認(rèn)false
    public boolean onTouchEvent(MotionEvent event) {
        return super.onTouchEvent(event);
    }
  • dispatchTouchEvent:Android所有的事件都經(jīng)過(guò)此方法分發(fā),返回true則表示對(duì)事件不再進(jìn)行分發(fā),事件沒(méi)有被消費(fèi),返回false則繼續(xù)往下分發(fā),如果是ViewGroup,則分發(fā)給onInterceptTouchEvent決定事件繼續(xù)分發(fā)還是被攔截
  • onInterceptTouchEvent:解決滑動(dòng)沖突的外部攔截法,是ViewGroup中特有的方法,決定觸摸事件是否攔截,返回true則表示攔截事件的分發(fā),交給自身的onTouchEvent進(jìn)行處理,返回false,則事件繼續(xù)向下分發(fā)
  • onTouchEvent:Android的觸摸事件消費(fèi),返回true,則表示當(dāng)前View處理該事件,返回false,則事件繼續(xù)進(jìn)行分發(fā),子View處理事件的優(yōu)先級(jí)比父View處理事件的優(yōu)先級(jí)要高
  • requestDisallowInterceptTouchEvent:解決滑動(dòng)沖突的內(nèi)部攔截法,作用于dispatchTouchEvent,請(qǐng)求不允許攔截觸摸事件,有時(shí)候,子類并不希望父類攔截它的觸摸事件,想將觸摸事件交給自身處理,常用方式:view.getParent().requestDisallowInterceptTouchEvent(true);
  • 當(dāng)前View接收到的觸摸事件,可以通過(guò)調(diào)用dispatchTouchEvent方法,將觸摸事件傳遞給其他View,從而達(dá)到不同的View處理相同的觸摸事件,起到聯(lián)動(dòng)的效果,比如移動(dòng)A的時(shí)候,想讓B也同時(shí)移動(dòng),就可以把A的觸摸事件傳遞給B,讓B也處理這個(gè)觸摸事件
  • 通過(guò)事件分發(fā)機(jī)制實(shí)現(xiàn)不能左右滑動(dòng)的ViewPager
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;

public class NoScrollViewPager extends ViewPager {

    private boolean canScroll = false; //是否可以滑動(dòng)

    public NoScrollViewPager(@NonNull Context context) {
        this(context,null);
    }

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

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (canScroll){
            return super.onInterceptTouchEvent(ev);
        }else{
            return false; -> 不攔截,讓事件繼續(xù)分發(fā)
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        if (canScroll){
            return super.onTouchEvent(ev);
        }else {
            return true; -> 消費(fèi)當(dāng)前事件
        }
    }
}

九、View的點(diǎn)擊事件

View的點(diǎn)擊事件設(shè)置只對(duì)單個(gè)View產(chǎn)生效果,比如設(shè)置ViewGroup的根布局不可點(diǎn)擊,ViewGroup的子View依然能接收點(diǎn)擊事件。而RelativeLayout等常用布局,設(shè)置根布局不可點(diǎn)擊,所有子View都不會(huì)處理點(diǎn)擊事件。在布局強(qiáng)轉(zhuǎn)成ViewGroup時(shí),部分功能會(huì)失效,比如設(shè)置該布局不可點(diǎn)擊,需要遍歷所有子View并為其設(shè)置不可點(diǎn)擊事件
view.setEnabled(true/false);

十、獲取View的寬高

View的measure過(guò)程與Activity的生命周期不是同步執(zhí)行的,在onCreat(),onStart(),onResume()中獲取View的寬高為零,原因是測(cè)量還沒(méi)完成
View初始化完畢時(shí)觸發(fā)
    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        if (hasFocus){
            int width = view.getMeasuredWidth();
            int height = view.getMeasuredHeight();
        }
    }
投遞一個(gè)任務(wù)到消息隊(duì)列的尾部
    view.post(new Runnable){
          @Override
          public void run(){
            int width = view.getMeasuredWidth();
            int height = view.getMeasuredHeight();
          }
    } 
View樹(shù)的狀態(tài)發(fā)生改變或者View樹(shù)的內(nèi)部View的可見(jiàn)性發(fā)生改變時(shí)觸發(fā)
        ViewTreeObserver observer = view.getViewTreeObserver();
        observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
               int width = view.getMeasuredWidth();
               int height = view.getMeasuredHeight(); 
            }
        });

十一、獲取View在屏幕中的位置

        int position[] = new int[2]; -> 0存x , 1存y 
        view.getLocationInWindow(position);
        //view.getLocationOnScreen(position);

        TextView tv = new TextView(this); -> 生成與屏幕位置一樣的View
        LayoutParams params = new LayoutParams(view.getLayoutParams());
        params.leftMargin = position[0];
        params.topMargin = position[1];
        view.setLayoutParams(params);
        viewGroup.addView(view);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,119評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,382評(píng)論 3 415
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 176,038評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,853評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,616評(píng)論 6 408
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,112評(píng)論 1 323
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,192評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,355評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,869評(píng)論 1 334
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,727評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,928評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,467評(píng)論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,165評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,570評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,813評(píng)論 1 282
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,585評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,892評(píng)論 2 372

推薦閱讀更多精彩內(nèi)容

  • 【Android 自定義View】 [TOC] 自定義View基礎(chǔ) 接觸到一個(gè)類,你不太了解他,如果貿(mào)然翻閱源碼只...
    Rtia閱讀 3,968評(píng)論 1 14
  • 目錄 1. 自定義View基礎(chǔ) 1.1 分類 自定義View的實(shí)現(xiàn)方式有以下幾種 類型定義自定義組合控件多個(gè)控件組...
    銀灬楓閱讀 189,421評(píng)論 21 535
  • 主要思路 1.我們需要自定義一個(gè)繼承自FrameLayout的布局,利用FrameLayout布-局的特性(在同一...
    ZebraWei閱讀 2,304評(píng)論 0 5
  • 本篇會(huì)講解view的onMeasure的詳細(xì)流程 onMeasure什么時(shí)候會(huì)被調(diào)用 onMeasure方法的作用...
    李慶雪閱讀 31,321評(píng)論 1 50
  • 母親說(shuō):只要有芝麻吃,生活總不會(huì)太差。 前幾日拿出來(lái)要炒的芝麻,放在桌子上,想著要抽時(shí)間撿干凈。只是第二天還沒(méi)來(lái)得...
    Someoner閱讀 814評(píng)論 3 3