2018-03-08

Android自定義HorizontalScrollView和ImageView實現不一樣的輪播圖效果

需求效果

最近在項目中需要實現一種跟大家在平時看到的大部分項目中不一樣的輪播圖的效果,圖片在屏幕中可快速滑動切換顯示,并且在滑動過程中,圖片旋轉角度并且逐漸變黑白圖片,滑動停止后通過計算圖片中心點距離屏幕中心距離最近的圖片居中顯示,顯示正常彩色和不旋轉角度;展示然后花了一些時間通過自定義HorizontalScrollView和ImageView最終實現了效果,特此進行記錄下來,效果如下面所示:


HorizontalScrollView實現滾動狀態監聽

首先自定義HorizontalScrollView有三種滾動狀態,包括IDLE(滾動停止),TOUCH_SCROLL(手指拖動滾動)和手指拖動離開界面后自動滾動 FLING(滾動);接著重寫onTouchEvent事件,MotionEvent.ACTION_MOVE表示手指在屏幕上滑動,此時滾動狀態為ScrollStatus.TOUCH_SCROLL;MotionEvent.ACTION_UP表示手指離開了屏幕,通過mHandler.post(scrollRunnable)進行滾動狀態監聽,此時滾動狀態有兩種情況,一個是ScrollStatus.IDLE滾動停止了,另一個是ScrollStatus.FLING還在自動滾動中,間隔一段時間通過判斷getScrollX() == currentX是否為true,如果為true則表示當前滾動停止了,如果為false則表示還在滾動中,代碼如下:

/**
 * 滾動狀態:
 * IDLE=滾動停止
 * TOUCH_SCROLL=手指拖動滾動
 * FLING=滾動
 */
public enum ScrollStatus {
    IDLE,
    TOUCH_SCROLL,
    FLING
}

/**
 * 記錄當前滾動的距離
 */
private int currentX = 0;

/**
 * 當前滾動狀態
 */
private ScrollStatus scrollStatus = ScrollStatus.IDLE;

private ScrollStatusListener mScrollStatusListener;

public interface ScrollStatusListener {
    void onScrollChanged(ScrollStatus scrollStatus);
}

public void setScrollStatusListener(ScrollStatusListener scrollStatusListener) {
    this.mScrollStatusListener = scrollStatusListener;
}

/**
 * 滾動狀態監聽runnable
 */
private Runnable scrollRunnable = new Runnable() {
    @Override
    public void run() {
        if (getScrollX() == currentX) {
            //滾動停止,取消監聽線程
            scrollStatus = ScrollStatus.IDLE;
            if (mScrollStatusListener != null) {
                mScrollStatusListener.onScrollChanged(scrollStatus);
            }
            mHandler.removeCallbacks(this);
            return;
        } else {
            //手指離開屏幕,但是view還在滾動
            scrollStatus = ScrollStatus.FLING;
            if (mScrollStatusListener != null) {
                mScrollStatusListener.onScrollChanged(scrollStatus);
            }
        }
        currentX = getScrollX();
        //滾動監聽間隔:milliseconds
        mHandler.postDelayed(this, 50);
    }
};

@Override
public boolean onTouchEvent(MotionEvent ev) {
    switch (ev.getAction()) {
        case MotionEvent.ACTION_MOVE:
            this.scrollStatus = ScrollStatus.TOUCH_SCROLL;
            if (mScrollStatusListener != null) {
                mScrollStatusListener.onScrollChanged(scrollStatus);
            }
            mHandler.removeCallbacks(scrollRunnable);
            break;
        case MotionEvent.ACTION_UP:
            mHandler.post(scrollRunnable);
            break;
    }
    return super.onTouchEvent(ev);
}

在實現HorizontalScrollView狀態監聽的同時,還需要實現它的滾動監聽,以便得到它的滾動值scrollX來計算得到每個ImageView需要的旋轉角度;如果調用ScrollVew.setScrollViewListener實現滾動監聽,則需要Android6.0及6.0以上

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    hsScroll.setOnScrollChangeListener(new View.OnScrollChangeListener() {
        @Override
        public void onScrollChange(View view, int scrollX, int scrollY, int oldScrollX, 
                                    int oldScrollY) {

        }
    });
}

所以需要向下做兼容處理,ScrollView不能像其他組件一樣使用onScrollChanged()方法是因為它被protected修飾了,所以只需要在CustomHorizontalScrollView做下封裝即可

private ScrollViewListener scrollViewListener = null;

//滾動監聽
public interface ScrollViewListener {
    void onScrollChanged(View chsv, int scrollX, int scrollY, int oldScrollX, int oldScrollY);
}

public void setScrollViewListener(ScrollViewListener scrollViewListener) {
    this.scrollViewListener = scrollViewListener;
}

@Override
protected void onScrollChanged(int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
    super.onScrollChanged(scrollX, scrollY, oldScrollX, oldScrollY);
    if (scrollViewListener != null) {
        scrollViewListener.onScrollChanged(this, scrollX, scrollY, oldScrollX, oldScrollY);
    }
}

自定義ImageView實現旋轉和黑白處理

ImageView旋轉可以通過矩陣Matrix來實現,對于矩陣大家應該都知道,百度或Google也可以搜到一大把的資料,這邊我就不說了,圖片彩色和黑白的處理切換可以通過顏色矩陣ColorMatrix設置飽和度來處理,當然效果和完全的黑白圖片還是有一點點差距的,但是如果真的要使用彩色圖片變成黑白圖片想到有兩種實現方案,一種是通過對像素點進行處理,我也試過很多的方法來處理,但是效率都是太低且會出現卡頓,這樣就無法實現絲滑快速滾動切換了;還有一種就是使用黑白圖片和彩色圖片疊在一起,然后給彩色圖片根據旋轉角度值進行設置透明度,這種方案實現也不好,實現麻煩并且圖片在項目中大部分都是需要從網絡上進行加載的,這樣處理起來的效率會很低了;用設置飽和度的方法我覺得是最好的了,可見上面的演示或者在底部點擊下載Demo查看效果

@Override
protected void onDraw(Canvas canvas) {
    int width = getWidth();
    int height = getHeight();
    if (mNewBmp == null) {
        mNewBmp = createBmp(mShowBmp, width, height);
        centerX = mNewBmp.getWidth() / 2;
        centerY = mNewBmp.getHeight() / 2;
    }
    mCamera.save();
    //繞Y軸翻轉
    mCamera.rotateY(mDegree);
    //設置camera作用矩陣
    mCamera.getMatrix(mMatrix);
    mCamera.restore();
    //設置翻轉中心點
    mMatrix.preTranslate(-this.centerX, -this.centerY);
    mMatrix.postTranslate(this.centerX, this.centerY);
    Paint paint = new Paint();
    // 透明度
    paint.setAlpha((int) (255 - Math.abs(mDegree) * 6));
    // 灰色
    ColorMatrix colorMatrix = new ColorMatrix();
    float grey = 1f - Math.abs((float) mDegree / 15f);
    if (grey < 0) {
        grey = 0;
    }
    colorMatrix.setSaturation(grey);
    ColorMatrixColorFilter colorMatrixFilter = new ColorMatrixColorFilter(colorMatrix);
    paint.setColorFilter(colorMatrixFilter);
    canvas.drawBitmap(mNewBmp, mMatrix, paint);
}

public Bitmap createBmp(Bitmap bm, int newWidth, int newHeight) {
    // 獲得圖片的寬高
    int width = bm.getWidth();
    int height = bm.getHeight();
    // 計算縮放比例
    float scaleWidth = ((float) newWidth) / width;
    float scaleHeight = ((float) newHeight) / height;
    // 取得想要縮放的matrix參數
    Matrix matrix = new Matrix();
    matrix.postScale(scaleWidth, scaleHeight);
    // 得到新的圖片
    Bitmap newBmp = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, true);
    return newBmp;
}

/**
 * 設置旋轉角度
 * @param degree
 */
public void setDegree(float degree) {
    mDegree = degree;
    invalidate();
}      

主工程main

直接上代碼,代碼中已經進行了很詳細的注釋了,甚至有點啰嗦了,但為了能夠一眼看懂,我也是操碎了心的。

layout.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:background="#FF99CC"
    android:orientation="vertical">

    <com.clay.slideshowdemo.view.CustomHorizontalScrollView
        android:id="@+id/hs_scroll"
        android:layout_width="match_parent"
        android:layout_height="350dp"
        android:layout_marginTop="50dp"
        android:scrollbars="none">

        <LinearLayout
            android:id="@+id/ll_shifting"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center"
            android:orientation="horizontal">

            <com.clay.slideshowdemo.view.RotateImageView
                android:id="@+id/riv_first"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:scaleType="centerCrop"
                android:src="@drawable/picture_a" />

            <com.clay.slideshowdemo.view.RotateImageView
                android:id="@+id/riv_second"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:scaleType="centerCrop"
                android:src="@drawable/picture_b" />

            <com.clay.slideshowdemo.view.RotateImageView
                android:id="@+id/riv_third"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:scaleType="centerCrop"
                android:src="@drawable/picture_c" />

            <com.clay.slideshowdemo.view.RotateImageView
                android:id="@+id/riv_fourth"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:scaleType="centerCrop"
                android:src="@drawable/picture_d" />

            <com.clay.slideshowdemo.view.RotateImageView
                android:id="@+id/riv_fifth"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:scaleType="centerCrop"
                android:src="@drawable/picture_e" />

            <com.clay.slideshowdemo.view.RotateImageView
                android:id="@+id/riv_sixth"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:scaleType="centerCrop"
                android:src="@drawable/picture_f" />

            <com.clay.slideshowdemo.view.RotateImageView
                android:id="@+id/riv_seventh"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:scaleType="centerCrop"
                android:src="@drawable/picture_g" />

            <com.clay.slideshowdemo.view.RotateImageView
                android:id="@+id/riv_eighth"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:scaleType="centerCrop"
                android:src="@drawable/picture_h" />

        </LinearLayout>

    </com.clay.slideshowdemo.view.CustomHorizontalScrollView>

    <LinearLayout
        android:id="@+id/dot_layout"
        android:layout_width="match_parent"
        android:layout_height="20dp"
        android:layout_marginTop="6dp"
        android:gravity="center"
        android:orientation="horizontal" />

</LinearLayout>

在Activity中使用

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    RotateImageView[] arrImgs = new RotateImageView[8];
    private CustomHorizontalScrollView chsvScroll;
    private LinearLayout llShifting;
    private LinearLayout dotLayout;         //輪播圖跟著滑動的點
    private int mLocation = 0;               //位置居中的條目
    private boolean mPositiveCycle = true;   //循環的方向
    private int mScreenWidth;                // 獲取屏幕寬度
    private static final int ROTATE_ANGLE = 15;     //角度
    private int mScreenWidthHalf = 0;
    Map<Integer, Integer> mLeftMap = new HashMap<>();  //保存每條條目中心距離HorizontalScrollView的最左邊的距離

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (msg.what == 1) {
                if (mLocation == 0) {
                    mPositiveCycle = true;
                } else if (mLocation == arrImgs.length - 1) {
                    mPositiveCycle = false;
                }
                if (mPositiveCycle) {
                    setCurrentCenter(mLocation + 1);
                } else {
                    setCurrentCenter(mLocation - 1);
                }
                mHandler.sendEmptyMessageDelayed(1, 6000);
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initView();
        initData();
        initListener();
    }

    private void initView() {
        chsvScroll = (CustomHorizontalScrollView) findViewById(R.id.hs_scroll);
        llShifting = (LinearLayout) findViewById(R.id.ll_shifting);
        dotLayout = (LinearLayout) findViewById(R.id.dot_layout);

        arrImgs[0] = (RotateImageView) findViewById(R.id.riv_first);
        arrImgs[1] = (RotateImageView) findViewById(R.id.riv_second);
        arrImgs[2] = (RotateImageView) findViewById(R.id.riv_third);
        arrImgs[3] = (RotateImageView) findViewById(R.id.riv_fourth);
        arrImgs[4] = (RotateImageView) findViewById(R.id.riv_fifth);
        arrImgs[5] = (RotateImageView) findViewById(R.id.riv_sixth);
        arrImgs[6] = (RotateImageView) findViewById(R.id.riv_seventh);
        arrImgs[7] = (RotateImageView) findViewById(R.id.riv_eighth);
    }

    private void initData() {
        mScreenWidth = getResources().getDisplayMetrics().widthPixels;
        mScreenWidthHalf = mScreenWidth / 2;
        // 設置每個條目的寬為屏幕的一半
        for (int i = 0; i < arrImgs.length; i++) {
            ViewGroup.LayoutParams layoutParams = arrImgs[i].getLayoutParams();
            layoutParams.width = mScreenWidthHalf;
            arrImgs[i].setLayoutParams(layoutParams);
        }
        //設置llShifting的leftPadding和rightPadding值為屏幕寬度的1/4,使RotateImageView居中顯示
        int shifting = mScreenWidth / 4;
        llShifting.setPadding(shifting, 0, shifting, 0);
        //記錄每個RotateImageView的中心到其父view的左邊的距離,是為了以后滑動時計算每個RotateImageView的旋轉角度
        for (int i = 0; i < arrImgs.length; i++) {
            int left = arrImgs[i].getLeft();
            //因為view在oncreate中還沒繪制,所以無法獲取arrImgs[i].getLeft的值,
            //可通過View.Post(Runnable)等到繪制完成后獲取arrImgs[i].getLeft
            //但在此項目中,arrImgs[i].getLeft是可預知的,因為已設置了每個arrImgs[i]的寬度和其在屏幕中的顯示位置,
            mLeftMap.put(i, mScreenWidthHalf * (i + 1));
        }
        //初始化條目所在的位置點
        initDots();
        //設置每個RotateImageView的旋轉角度
        setRotateAngle(0);
        //設置第一個RotateImageView居中
        setCurrentCenter(0);
    }

    private void initListener() {
        arrImgs[0].setOnClickListener(this);
        arrImgs[1].setOnClickListener(this);
        arrImgs[2].setOnClickListener(this);
        arrImgs[3].setOnClickListener(this);
        arrImgs[4].setOnClickListener(this);
        arrImgs[5].setOnClickListener(this);
        arrImgs[6].setOnClickListener(this);
        arrImgs[7].setOnClickListener(this);

        // 滾動狀態監聽
        chsvScroll.setScrollStatusListener(new CustomHorizontalScrollView.ScrollStatusListener() {
            @Override
            public void onScrollChanged(CustomHorizontalScrollView.ScrollStatus scrollStatus) {
                //手勢滾動時不要進行自動輪播
                mHandler.removeMessages(1);
                //滾動停止,然后計算每個arrImgs[i]的中心到屏幕的mScreenWidthHalf的距離,對比得到最小值,從而求出滑動停止后需要居中不旋轉角度的arrImgs[mLocation]
                if (scrollStatus == CustomHorizontalScrollView.ScrollStatus.IDLE) {
                    int scrollX = chsvScroll.getScrollX();
                    int position = 0;
                    //計算屏幕中心距離CustomHorizontalScrollView左邊的距離
                    int stopCenterScroll = mScreenWidthHalf + scrollX;
                    int distanceCenterMin = Math.abs(mLeftMap.get(0) - stopCenterScroll);
                    for (int i = 1; i < arrImgs.length; i++) {
                        int left = mLeftMap.get(i);
                        int value = Math.abs(stopCenterScroll - left);
                        if (value < distanceCenterMin) {
                            position = i;
                            distanceCenterMin = value;
                        }
                    }
                    setCurrentCenter(position);
                    //滾動停止后繼續進行自動輪播
                    mHandler.sendEmptyMessageDelayed(1, 6000);
                }
            }
        });

        //滾動監聽
        chsvScroll.setScrollViewListener(new CustomHorizontalScrollView.ScrollViewListener() {
            @Override
            public void onScrollChanged(View chsv, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
                setRotateAngle(scrollX);
            }
        });
    }

    /**
     * 初始化跟條目相對應的點
     */
    private void initDots() {
        for (int i = 0; i < arrImgs.length; i++) {
            View view = new View(this);
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(Utils.dp2Px(this, 14), Utils.dp2Px(this, 6));
            if (i != 0) {
                params.leftMargin = Utils.dp2Px(this, 5);
            }
            view.setLayoutParams(params);
            view.setBackgroundResource(R.drawable.selector_dot);
            dotLayout.addView(view);
        }
        mHandler.sendEmptyMessageDelayed(1, 6000);
    }

    /**
     * 更新點
     */
    private void updateIntroAndDot(int position) {
        for (int i = 0; i < dotLayout.getChildCount(); i++) {
            dotLayout.getChildAt(i).setEnabled(i == position);
        }
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.riv_first:
                setCurrentCenter(0);
                Toast.makeText(this, "position : 0", Toast.LENGTH_SHORT).show();
                break;
            case R.id.riv_second:
                setCurrentCenter(1);
                Toast.makeText(this, "position : 1", Toast.LENGTH_SHORT).show();
                break;
            case R.id.riv_third:
                setCurrentCenter(2);
                Toast.makeText(this, "position : 2", Toast.LENGTH_SHORT).show();
                break;
            case R.id.riv_fourth:
                setCurrentCenter(3);
                Toast.makeText(this, "position : 3", Toast.LENGTH_SHORT).show();
                break;
            case R.id.riv_fifth:
                setCurrentCenter(4);
                Toast.makeText(this, "position : 4", Toast.LENGTH_SHORT).show();
                break;
            case R.id.riv_sixth:
                setCurrentCenter(5);
                Toast.makeText(this, "position : 5", Toast.LENGTH_SHORT).show();
                break;
            case R.id.riv_seventh:
                setCurrentCenter(6);
                Toast.makeText(this, "position : 6", Toast.LENGTH_SHORT).show();
                break;
            case R.id.riv_eighth:
                setCurrentCenter(7);
                Toast.makeText(this, "position : 7", Toast.LENGTH_SHORT).show();
                break;
        }
    }

    /**
     * 設置每個RotateImageView的旋轉角度
     *
     * @param scrollX
     */
    public void setRotateAngle(int scrollX) {
        for (int i = 0; i < arrImgs.length; i++) {
            //旋轉角度 = (HorizontalScrollView的x軸方向偏移量 + 屏幕寬度的一半 - RotateImageView的中心距父view的最左邊距離) * 旋轉角度 / 屏幕寬度的一半
            int degree = (scrollX + mScreenWidthHalf - mLeftMap.get(i)) * ROTATE_ANGLE / mScreenWidthHalf;
            arrImgs[i].setDegree(degree);
        }
    }

    /**
     * 設置滾動停止后需要居中的position以及更新點
     *
     * @param position
     */
    public void setCurrentCenter(int position) {
        //記錄當前條目
        mLocation = position;
        //計算控件居正中時距離左側屏幕的距離
        int middleLeftPosition = (mScreenWidth - arrImgs[position].getWidth()) / 2;
        //需要顯示在正中間位置的position需要向左偏移的距離
        int left = arrImgs[position].getLeft();
        int offset = left - middleLeftPosition;
        //讓水平的滾動視圖按照執行的x的偏移量進行移動
        chsvScroll.smoothScrollTo(offset, 0);
        //更新點
        updateIntroAndDot(position);
    }
}

可結合下面這張圖可以更好的進行理解

大家可以想象成一個長方形的長紙條放在手機屏幕上進行左右方向的拖動,其中長方形左右兩邊各留出寬度是屏幕四分之一的空白處(這是為了第一個和最后一個能夠居中顯示),其余部分等分成多個小長方形,其中每個小長方形的寬度都是屏幕的一半(這個都是可以自己調節,只需要保證每個小長方形的寬度相同即可,邏輯通了,其它就好辦多了),然后給手機屏幕中心和各個小長方形中心進行瞄點,然后拖動,當拖動停止后通過判斷長紙條中哪個小長方形的中心距離屏幕中心點最近,即可設置滾動停止后需要居中的小長方形(這就是設置滾動狀態監聽停止后的邏輯代碼需要實現的結果);至于小長方形的旋轉角度則根據小長方形左右拖動時小長方形中心點距離原來未拖動時的中心點所在位置的的距離進行計算的(即是HorizontalScroll的scrollX)。

GitHub傳送門,如何覺得還可以,歡迎star~

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,321評論 6 543
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,559評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,442評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,835評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,581評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,922評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,931評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,096評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,639評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,374評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,591評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,104評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,789評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,196評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,524評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,322評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,554評論 2 379

推薦閱讀更多精彩內容

  • 一,HTML語言的一般語法: 1,圍堵標記:<>… 1)帶屬性的標記: … 2)無屬性的標記:加粗 居中 標題 2...
    清水易藍閱讀 1,281評論 0 2
  • 圖表控件庫 MPAndroidChart 的使用 使用方法 項目源碼地址,包含了很多類型的圖標 https://g...
    jinchuang閱讀 834評論 0 0
  • 編譯過程分為四個步驟 1.預處理(Pre-process) 把宏替換刪除注釋展開頭文件產生 .i 文件 2.編譯 ...
    琦均煞Sylar閱讀 1,182評論 0 0
  • 臘月茫茫又倦床。余草恰疑東風忙。 白茶勿攪夜來醉,淚盡更憐枝頭霜。 夢已逝,情漸傷。 枯山漫步卻孤涼。 偏又不忍惹...
    暮衍情閱讀 286評論 0 3
  • 那是一條靈動的長河 碧綠,活潑 幼年時 在岸邊奔跑,聽水聲自水面回響 清脆,叮咚 青年時 沿岸邊漫步 看魚兒自水底...
    小森林哈閱讀 181評論 0 1