Android 輪播圖-自定義樣式

Android 輪播圖--自定義輪播界面樣式

百度關(guān)鍵字“輪播圖”可以搜到各種各樣的文章和實(shí)現(xiàn)方法竞阐。簡單的輪播效果隨手就來,這篇文章之后我會一直更新,直到自己可以游刃有余的實(shí)現(xiàn)各種炫酷的UI為止吉捶。

我們常說:有輪子為啥要自己造輪子停士。但是用別人寫好的輪子,自己也要吃透它循捺,不然如何應(yīng)對UI設(shè)計(jì)師擂涛。

github上有好多寫好的框架丢氢,結(jié)合自己的需求和排行爱致,我選用了ConvenientBanner烤送。

先放效果圖:


image.png

第一步,集成:

在app build.gradle中添加:implementation'com.bigkoo:ConvenientBanner:2.1.4'

第二步糠悯,activity_main.xml中添加控件,以及自定義item布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">


    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="200dp">

        <ImageView
            android:id="@+id/bg_img"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="centerCrop"/>

        <com.bigkoo.convenientbanner.ConvenientBanner
            android:id="@+id/convenientBanner"
            android:layout_width="match_parent"
            android:layout_height="200dp"
            app:canLoop="true" />
    </RelativeLayout>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.example.myapplication4.ClipRoundImageView
        android:id="@+id/item_img"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="30dp"
        android:scaleType="centerCrop"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:radius="10dp" />

</android.support.constraint.ConstraintLayout>

上面布局中用到的RoundImageView妻往,順便也貼出來,兩種方法都發(fā)出來互艾,可根據(jù)自己喜好選擇

package com.example.myapplication4;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Path;
import android.os.Build;
import androidx.appcompat.widget.AppCompatImageView;
import android.util.AttributeSet;
import android.view.View;

public class ClipRoundImageView extends AppCompatImageView {


    private int width;
    private int height;

    private Path path;

    private int defaultRadius = 0;
    private int radius;
    private int leftTopRadius;
    private int rightTopRadius;
    private int rightBottomRadius;
    private int leftBottomRadius;

    public ClipRoundImageView(Context context) {
        this(context,null);
    }

    public ClipRoundImageView(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public ClipRoundImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        if (Build.VERSION.SDK_INT < 18) {
            setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        }
        // 讀取配置
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.Custom_Round_Image_View);
        radius = array.getDimensionPixelOffset(R.styleable.Custom_Round_Image_View_radius, defaultRadius);
        leftTopRadius = array.getDimensionPixelOffset(R.styleable.Custom_Round_Image_View_left_top_radius, defaultRadius);
        rightTopRadius = array.getDimensionPixelOffset(R.styleable.Custom_Round_Image_View_right_top_radius, defaultRadius);
        rightBottomRadius = array.getDimensionPixelOffset(R.styleable.Custom_Round_Image_View_right_bottom_radius, defaultRadius);
        leftBottomRadius = array.getDimensionPixelOffset(R.styleable.Custom_Round_Image_View_left_bottom_radius, defaultRadius);

        //如果四個角的值沒有設(shè)置,那么就使用通用的radius的值讯泣。
        if (defaultRadius == leftTopRadius) {
            leftTopRadius = radius;
        }
        if (defaultRadius == rightTopRadius) {
            rightTopRadius = radius;
        }
        if (defaultRadius == rightBottomRadius) {
            rightBottomRadius = radius;
        }
        if (defaultRadius == leftBottomRadius) {
            leftBottomRadius = radius;
        }
        array.recycle();
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        width = getWidth();
        height = getHeight();
    }

    @Override
    protected void onDraw(Canvas canvas) {

        path = new Path();
        int maxLeft = Math.max(leftTopRadius, leftBottomRadius);
        int maxRight = Math.max(rightTopRadius, rightBottomRadius);
        int minWidth = maxLeft + maxRight;
        int maxTop = Math.max(leftTopRadius, rightTopRadius);
        int maxBottom = Math.max(leftBottomRadius, rightBottomRadius);
        int minHeight = maxTop + maxBottom;
        if (width >= minWidth && height > minHeight) {
            Path path = new Path();
            //四個圓角
            path.moveTo(leftTopRadius, 0);
            path.lineTo(width - rightTopRadius, 0);
            path.quadTo(width, 0, width, rightTopRadius);

            path.lineTo(width, height - rightBottomRadius);
            path.quadTo(width, height, width - rightBottomRadius, height);

            path.lineTo(leftBottomRadius, height);
            path.quadTo(0, height, 0, height - leftBottomRadius);

            path.lineTo(0, leftTopRadius);
            path.quadTo(0, 0, leftTopRadius, 0);

            canvas.clipPath(path);
        }


        super.onDraw(canvas);
    }
}

package com.example.myapplication4;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.AppCompatImageView;
import android.util.AttributeSet;

@SuppressLint("AppCompatCustomView")
public class RoundImageView extends AppCompatImageView {


    private int mBorderRadius = 60;
    private Paint mPaint;
    private Matrix matrix;
    private BitmapShader mBitmapShader;

    public RoundImageView(Context context) {
        this(context,null);
    }

    public RoundImageView(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public RoundImageView(Context context,  AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        matrix = new Matrix();
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if(null == getDrawable()){
            return;
        }
        Bitmap bitmap = drawableToBitamp(getDrawable());
        mBitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
        float scale = 1.0f;
        if(!(bitmap.getWidth() == getWidth() && bitmap.getHeight() == getHeight())) {
            // 如果圖片的寬或者高與view的寬高不匹配纫普,計(jì)算出需要縮放的比例;縮放后的圖片的寬高好渠,一定要大于我們view的寬高昨稼;所以我們這里取大值;
            scale = Math.max(getWidth() * 1.0f / bitmap.getWidth(), getHeight() * 1.0f / bitmap.getHeight());
        }
        matrix.setScale(scale,scale);
        mBitmapShader.setLocalMatrix(matrix);
        canvas.drawRoundRect(new RectF(0,0, getWidth(), getHeight()), mBorderRadius,mBorderRadius,mPaint);

        super.onDraw(canvas);
    }

    private Bitmap drawableToBitamp(Drawable drawable){

        if(drawable instanceof BitmapDrawable){
            BitmapDrawable bd = (BitmapDrawable) drawable;
            return bd.getBitmap();
        }
        //當(dāng)設(shè)置不為圖片時拳锚,即為顏色時假栓,獲取控件的寬度
        int w = drawable.getIntrinsicWidth() <= 0 ? getWidth() : drawable.getIntrinsicWidth();
        int h = drawable.getIntrinsicHeight() <= 0 ? getHeight() : drawable.getIntrinsicHeight();
        Bitmap bitmap = Bitmap.createBitmap(w,h, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0,0, w, h);
        drawable.draw(canvas);
        return bitmap;
    }
}

接下來就是MainActivity中的Java代碼實(shí)現(xiàn)了

package com.example.myapplication4;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;

import com.bigkoo.convenientbanner.ConvenientBanner;
import com.bigkoo.convenientbanner.holder.CBViewHolderCreator;
import com.bigkoo.convenientbanner.holder.Holder;
import com.bigkoo.convenientbanner.listener.OnItemClickListener;
import com.bumptech.glide.Glide;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";


    private ImageView bgImg;

    private ConvenientBanner convenientBanner;


    private List<Integer> localImages = new ArrayList<Integer>();


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        localImages.add(R.mipmap.chengxi);
        localImages.add(R.mipmap.jinping);
        localImages.add(R.mipmap.qilihe);

        bgImg = findViewById(R.id.bg_img);

        Glide.with(MainActivity.this)
                .load("http://www.pptbz.com/pptpic/UploadFiles_6909/201203/2012031220134655.jpg")
                .into(bgImg);


        convenientBanner = findViewById(R.id.convenientBanner);
        convenientBanner.setPages(new CBViewHolderCreator() {
            @Override
            public Holder createHolder(View itemView) {
                return new LocalImageHolderView(itemView);
            }

            @Override
            public int getLayoutId() {
                return R.layout.item_localimage;
            }
        }, localImages);
        //設(shè)置兩個點(diǎn)圖片作為翻頁指示器,不設(shè)置則沒有指示器霍掺,可以根據(jù)自己需求自行配合自己的指示器,不需要圓點(diǎn)指示器可用不設(shè)
        convenientBanner.setPageIndicator(new int[]{R.drawable.unseclect_dot, R.drawable.seclect_dot});
        convenientBanner.setPageIndicatorAlign(ConvenientBanner.PageIndicatorAlign.CENTER_HORIZONTAL);
        convenientBanner.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(int position) {
                Toast.makeText(MainActivity.this, "點(diǎn)擊了第" + position + "個圖片", Toast.LENGTH_SHORT).show();
            }
        });

    }

    @Override
    protected void onResume() {
        super.onResume();
        convenientBanner.startTurning();
    }

    @Override
    protected void onPause() {
        super.onPause();
        convenientBanner.stopTurning();
    }

    class LocalImageHolderView extends Holder<Integer> {
        private ClipRoundImageView imageView;

        public LocalImageHolderView(View itemView) {
            super(itemView);
        }

        @Override
        protected void initView(View itemView) {
            imageView = itemView.findViewById(R.id.item_img);

        }

        @Override
        public void updateUI(Integer data) {
            imageView.setImageResource(data);
        }
    }

attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="Custom_Round_Image_View">
        <attr name="radius" format="dimension"/>
        <attr name="left_top_radius" format="dimension"/>
        <attr name="right_top_radius" format="dimension"/>
        <attr name="right_bottom_radius" format="dimension"/>
        <attr name="left_bottom_radius" format="dimension"/>
    </declare-styleable>
</resources>

}

最后: 兩個小圓點(diǎn)是自己畫的unseclect_dot.xml, seclect_dot.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">
    <solid android:color="#333333" />
    <size android:height="5dp" android:width="5dp"/>
</shape>

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">
    <solid android:color="#cccccc" />
    <size android:height="5dp" android:width="5dp"/>
</shape>

待續(xù)......

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末匾荆,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子杆烁,更是在濱河造成了極大的恐慌牙丽,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,430評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件兔魂,死亡現(xiàn)場離奇詭異烤芦,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)析校,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評論 3 398
  • 文/潘曉璐 我一進(jìn)店門构罗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人勺良,你說我怎么就攤上這事绰播。” “怎么了尚困?”我有些...
    開封第一講書人閱讀 167,834評論 0 360
  • 文/不壞的土叔 我叫張陵蠢箩,是天一觀的道長。 經(jīng)常有香客問我,道長谬泌,這世上最難降的妖魔是什么滔韵? 我笑而不...
    開封第一講書人閱讀 59,543評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮掌实,結(jié)果婚禮上陪蜻,老公的妹妹穿的比我還像新娘。我一直安慰自己贱鼻,他們只是感情好宴卖,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,547評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著邻悬,像睡著了一般症昏。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上父丰,一...
    開封第一講書人閱讀 52,196評論 1 308
  • 那天肝谭,我揣著相機(jī)與錄音,去河邊找鬼蛾扇。 笑死攘烛,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的镀首。 我是一名探鬼主播坟漱,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼蘑斧!你這毒婦竟也來了靖秩?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,671評論 0 276
  • 序言:老撾萬榮一對情侶失蹤竖瘾,失蹤者是張志新(化名)和其女友劉穎沟突,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捕传,經(jīng)...
    沈念sama閱讀 46,221評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡惠拭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,303評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了庸论。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片职辅。...
    茶點(diǎn)故事閱讀 40,444評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖聂示,靈堂內(nèi)的尸體忽然破棺而出域携,到底是詐尸還是另有隱情,我是刑警寧澤鱼喉,帶...
    沈念sama閱讀 36,134評論 5 350
  • 正文 年R本政府宣布秀鞭,位于F島的核電站趋观,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏锋边。R本人自食惡果不足惜皱坛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,810評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望豆巨。 院中可真熱鬧剩辟,春花似錦、人聲如沸往扔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽萍膛。三九已至融欧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間卦羡,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評論 1 272
  • 我被黑心中介騙來泰國打工麦到, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留绿饵,地道東北人。 一個月前我還...
    沈念sama閱讀 48,837評論 3 376
  • 正文 我出身青樓瓶颠,卻偏偏與公主長得像拟赊,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子粹淋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,455評論 2 359

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

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫吸祟、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,118評論 4 61
  • 說到輪播圖桃移,想必大家都不陌生屋匕。常見的APP都會有一個圖片輪播的區(qū)域。之前使用過輪播圖借杰,最近項(xiàng)目又一次用到了过吻,就把原...
    IAM四十二閱讀 6,717評論 7 39
  • 主要思路 1.我們需要自定義一個繼承自FrameLayout的布局,利用FrameLayout布-局的特性(在同一...
    ZebraWei閱讀 2,292評論 0 5
  • 翻譯:中國學(xué)生申請赴美留學(xué)面臨的一大障礙是托刚岷猓考試纤虽。 TOEFL is a hurdle of studying ...
    Zeroun_Ph閱讀 134評論 0 0
  • 很多家長都會擔(dān)心孩子玩游戲上癮,尤其是寒暑假期間绞惦,但通常他們的做法是一禁了之逼纸,結(jié)果導(dǎo)致孩子逆反,反而更加沉迷于游戲...
    付四清閱讀 125評論 0 0