最近事情不是很多,在家無聊的時候看看直播,總能看到一些新奇的驗證登錄方式,正好自己最近也要去熟悉一下新的開發工具Android Studio,所以打算自己實現一下.
先看一下效果圖:
一、確認需求
首先我們確認一下需求,我們分步來看
1.)需要定義一個陰影部分去遮蓋圖片,確定一個目標位置.
2.)需要一個帶有邊框的滑塊內容,初始位置在最左邊.
3.)陰影部分和滑塊可以隨機旋轉,並保持一致.
4.)需要一個拖拽條使滑塊隨着拖拽條條拖拽而移動
5.)判斷是否驗證成功
二、分析問題
第一點,很簡單我們只需要一直帶有透明度的陰影圖片,隨機的去覆蓋在圖像上就可以實現.
第二點,需要用到畫筆的setXfermode方法來設置圖片疊加的顯示模式.從而顯示出一個帶有邊框的滑塊.
第三點,需要改變圖片的matrix來實現對圖像的旋轉.
第四點,安卓系統自帶的SeekBar可以實現拖拽條的功能.
第五點,只需對外提供一個回調接口,來判斷是否驗證成功即可.
三、代碼實現
首先創建一個attr文件來定義一些自定義屬性,方便我們使用
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--滑塊的高度-->
<attr name="unitHeight" format="dimension" />
<!--滑塊的寬度-->
<attr name="unitWidth" format="dimension" />
<!--滑塊佔圖片高度的比例-->
<attr name="unitHeightScale" format="integer" />
<!--滑塊佔圖片寬度的比例-->
<attr name="unitWidthScale" format="integer" />
<!--滑塊邊框的圖片資源-->
<attr name="unitShadeSrc" format="reference" />
<!--陰影部分的圖片資源-->
<attr name="unitShowSrc" format="reference" />
<!--是否需要旋轉-->
<attr name="needRotate" format="boolean" />
<!--驗證時的誤差值-->
<attr name="deviate" format="integer" />
<declare-styleable name="DouYuView">
<attr name="unitHeight" />
<attr name="unitWidth" />
<attr name="unitHeightScale" />
<attr name="unitWidthScale" />
<attr name="unitShadeSrc" />
<attr name="unitShowSrc" />
<attr name="needRotate" />
<attr name="deviate" />
</declare-styleable>
</resources>
然後我們創建一個DouYuView繼承自ImageView即可,來定義一下屬性
/**
* 定義畫筆
*/
private Paint mPaint;
/**
* 驗證的圖像
*/
private Bitmap mBitmap;
/**
* 驗證滑塊的高
*/
private int mUintHeight;
/**
* 驗證滑塊的寬
*/
private int mUintWidth;
/**
* 驗證滑塊寬佔用整體圖片大小的比例,默認1/5
*/
private int mUnitWidthScale;
/**
* 驗證滑塊高度佔用整體圖片大小的比例,默認1/4
*/
private int mUnitHeightScale;
/**
* 隨機生成滑塊的X座標
*/
private int mUnitRandomX;
/**
* 隨機生成滑塊的Y座標
*/
private int mUnitRandomY;
/***
* 滑塊移動的距離
*/
private float mUnitMoveDistance = 0;
/***
* 滑塊圖像
*/
private Bitmap mUnitBp;
/**
* 驗證位置圖像
*/
private Bitmap mShowBp;
/**
* 背景陰影圖像
*/
private Bitmap mShadeBp;
/**
* 是否需要旋轉
**/
private boolean needRotate;
/**
* 旋轉的角度
*/
private int rotate;
/**
* 判斷是否完成的偏差量,默認爲10
*/
public int DEFAULT_DEVIATE;
/**
* 判斷是否重新繪製圖像
*/
private boolean isReSet = true;
準備好這些之後,開始實現具體功能,這次我們打算用星星的圖片,來設置陰影和滑塊,首先我們準備兩張圖片,如下圖(注意,帶邊框的圖片中間部分,使用白色填充的):
爲了使圖片不會出現變形等異常,我們需要對圖片進行獲取及縮放的一些操作,代碼如下:
/**
* 獲取實際顯示的圖片
*
* @return
*/
public Bitmap getBaseBitmap() {
Bitmap b = drawableToBitamp(getDrawable());
float scaleX = 1.0f;
float scaleY = 1.0f;
// 如果圖片的寬或者高與view的寬高不匹配,計算出需要縮放的比例;縮放後的圖片的寬高,一定要大於我們view的寬高;所以我們這裏取大值;
scaleX = getWidth() * 1.0f / b.getWidth();
scaleY = getHeight() * 1.0f / b.getHeight();
Matrix matrix = new Matrix();
matrix.setScale(scaleX, scaleY);
Bitmap bd = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(),
matrix, true);
return bd;
}
/**
* drawable轉bitmap
*
* @param drawable
* @return
*/
private Bitmap drawableToBitamp(Drawable drawable) {
if (null == drawable) {
return null;
}
if (drawable instanceof BitmapDrawable) {
BitmapDrawable bd = (BitmapDrawable) drawable;
return bd.getBitmap();
}
int w = drawable.getIntrinsicWidth();
int h = 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;
}
/**
* 縮放圖片
*
* @param bp
* @param x
* @param y
* @return
*/
public static Bitmap handleBitmap(Bitmap bp, float x, float y) {
int w = bp.getWidth();
int h = bp.getHeight();
float sx = (float) x / w;
float sy = (float) y / h;
Matrix matrix = new Matrix();
matrix.postScale(sx, sy);
Bitmap resizeBmp = Bitmap.createBitmap(bp, 0, 0, w,
h, matrix, true);
return resizeBmp;
}
然後再去生成陰影圖像和滑塊
/**
* 創建遮擋的圖片(陰影部分)
*
* @return
*/
private Bitmap drawTargetBitmap() {
// 繪製圖片
Bitmap showB;
if (null != mShowBp) {
showB = handleBitmap(mShowBp, mUintWidth, mUintHeight);
} else {
showB = handleBitmap(BitmapFactory.decodeResource(getResources(), R.mipmap.puzzle_show), mUintWidth, mUintHeight);
}
// 如果需要旋轉圖片,進行旋轉,旋轉後爲了保持和滑塊大小一致,需要重新縮放比例
if (needRotate) {
showB = handleBitmap(rotateBitmap(rotate, showB), mUintWidth, mUintHeight);
}
return showB;
}
/**
* 創建結合的圖片(滑塊)
*
* @param bp
*/
private Bitmap drawResultBitmap(Bitmap bp) {
// 繪製圖片
Bitmap shadeB;
if (null != mShadeBp) {
shadeB = handleBitmap(mShadeBp, mUintWidth, mUintHeight);
} else {
shadeB = handleBitmap(BitmapFactory.decodeResource(getResources(), R.mipmap.puzzle_shade), mUintWidth, mUintHeight);
}
// 如果需要旋轉圖片,進行旋轉,旋轉後爲了和畫布大小保持一致,避免出現圖像顯示不全,需要重新縮放比例
if (needRotate) {
shadeB = handleBitmap(rotateBitmap(rotate, shadeB), mUintWidth, mUintHeight);
}
Bitmap resultBmp = Bitmap.createBitmap(mUintWidth, mUintHeight,
Bitmap.Config.ARGB_8888);
Paint paint = new Paint();
paint.setAntiAlias(true);
Canvas canvas = new Canvas(resultBmp);
canvas.drawBitmap(shadeB, new Rect(0, 0, mUintWidth, mUintHeight),
new Rect(0, 0, mUintWidth, mUintHeight), paint);
// 選擇交集去上層圖片
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
canvas.drawBitmap(bp, new Rect(0, 0, mUintWidth, mUintHeight),
new Rect(0, 0, mUintWidth, mUintHeight), paint);
return resultBmp;
}
準備好這些之後,還需要隨機生成一個顯示位置和對圖像進行旋轉的方法就可以在畫布上去畫出這些內容,代碼如下:
/**
* 隨機生成生成滑塊的XY座標
*/
private void initUnitXY() {
mUnitRandomX = (int) (Math.random() * (mBitmap.getWidth() - mUintWidth));
mUnitRandomY = (int) (Math.random() * (mBitmap.getHeight() - mUintHeight));
// 防止生成的位置距離太近
if (mUnitRandomX <= mBitmap.getWidth() / 2) {
mUnitRandomX = mUnitRandomX + mBitmap.getWidth() / 4;
}
// 防止生成的X座標截圖時導致異常
if (mUnitRandomX + mUintWidth > getWidth()) {
initUnitXY();
return;
}
}
/**
* 旋轉圖片
*
* @param degree
* @param bitmap
* @return
*/
public Bitmap rotateBitmap(int degree, Bitmap bitmap) {
Matrix matrix = new Matrix();
matrix.postRotate(degree);
Bitmap bm = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
bitmap.getHeight(), matrix, true);
return bm;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (isReSet) {
mBitmap = getBaseBitmap();
if (0 == mUintWidth) {
mUintWidth = mBitmap.getWidth() / mUnitWidthScale;
}
if (0 == mUintHeight) {
mUintHeight = mBitmap.getHeight() / mUnitHeightScale;
}
initUnitXY();
mUnitBp = Bitmap.createBitmap(mBitmap, mUnitRandomX, mUnitRandomY, mUintWidth, mUintHeight);
}
isReSet = false;
canvas.drawBitmap(drawTargetBitmap(), mUnitRandomX, mUnitRandomY, mPaint);
canvas.drawBitmap(drawResultBitmap(mUnitBp), mUnitMoveDistance, mUnitRandomY, mPaint);
}
我們還需要對控件進行重置、控制滑塊移動、提供回調方法判斷驗證是否成功等方法.
/**
* 重置
*/
public void reSet() {
isReSet = true;
mUnitMoveDistance = 0;
if (needRotate) {
rotate = (int) (Math.random() * 3) * 90;
} else {
rotate = 0;
}
invalidate();
}
/**
* 獲取每次滑動的平均偏移值
*
* @return
*/
public float getAverageDistance(int max) {
return (float) (mBitmap.getWidth() - mUintWidth) / max;
}
/**
* 滑塊移動距離
*
* @param distance
*/
public void setUnitMoveDistance(float distance) {
mUnitMoveDistance = distance;
// 防止滑塊滑出圖片
if (mUnitMoveDistance > mBitmap.getWidth() - mUintWidth) {
mUnitMoveDistance = mBitmap.getWidth() - mUintWidth;
}
invalidate();
}
/**
* 拼圖成功的回調
**/
interface onPuzzleListener {
public void onSuccess();
public void onFail();
}
/**
* 回調
*/
private onPuzzleListener mlistener;
/**
* 設置回調
*
* @param listener
*/
public void setPuzzleListener(onPuzzleListener listener) {
this.mlistener = listener;
}
/**
* 驗證是否拼接成功
*/
public void testPuzzle() {
if (Math.abs(mUnitMoveDistance - mUnitRandomX) <= DEFAULT_DEVIATE) {
if (null != mlistener) {
mlistener.onSuccess();
}
} else {
if (null != mlistener) {
mlistener.onFail();
}
}
}
基本上我們需要的功能就實現了.
四、完整的代碼及使用
DouYuView:
package com.example.junweiliu.douyutest;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.ImageView;
/**
* Created by junweiliu on 16/4/26.
*/
public class DouYuView extends ImageView {
/**
* 定義畫筆
*/
private Paint mPaint;
/**
* 驗證的圖像
*/
private Bitmap mBitmap;
/**
* 驗證滑塊的高
*/
private int mUintHeight;
/**
* 驗證滑塊的寬
*/
private int mUintWidth;
/**
* 驗證滑塊寬佔用整體圖片大小的比例,默認1/5
*/
private int mUnitWidthScale;
/**
* 驗證滑塊高度佔用整體圖片大小的比例,默認1/4
*/
private int mUnitHeightScale;
/**
* 隨機生成滑塊的X座標
*/
private int mUnitRandomX;
/**
* 隨機生成滑塊的Y座標
*/
private int mUnitRandomY;
/***
* 滑塊移動的距離
*/
private float mUnitMoveDistance = 0;
/***
* 滑塊圖像
*/
private Bitmap mUnitBp;
/**
* 驗證位置圖像
*/
private Bitmap mShowBp;
/**
* 背景陰影圖像
*/
private Bitmap mShadeBp;
/**
* 是否需要旋轉
**/
private boolean needRotate;
/**
* 旋轉的角度
*/
private int rotate;
/**
* 判斷是否完成的偏差量,默認爲10
*/
public int DEFAULT_DEVIATE;
/**
* 判斷是否重新繪製圖像
*/
private boolean isReSet = true;
/**
* 拼圖成功的回調
**/
interface onPuzzleListener {
public void onSuccess();
public void onFail();
}
/**
* 回調
*/
private onPuzzleListener mlistener;
/**
* 設置回調
*
* @param listener
*/
public void setPuzzleListener(onPuzzleListener listener) {
this.mlistener = listener;
}
public DouYuView(Context context) {
this(context, null);
}
public DouYuView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public DouYuView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.DouYuView);
mUintWidth = ta.getDimensionPixelOffset(R.styleable.DouYuView_unitHeight, 0);
mUintHeight = ta.getDimensionPixelOffset(R.styleable.DouYuView_unitHeight, 0);
mUnitHeightScale = ta.getInteger(R.styleable.DouYuView_unitHeightScale, 4);
mUnitWidthScale = ta.getInteger(R.styleable.DouYuView_unitWidthScale, 5);
Drawable showBp = ta.getDrawable(R.styleable.DouYuView_unitShowSrc);
mShowBp = drawableToBitamp(showBp);
Drawable shadeBp = ta.getDrawable(R.styleable.DouYuView_unitShadeSrc);
mShadeBp = drawableToBitamp(shadeBp);
needRotate = ta.getBoolean(R.styleable.DouYuView_needRotate, true);
DEFAULT_DEVIATE = ta.getInteger(R.styleable.DouYuView_deviate, 10);
ta.recycle();
// 初始化
mPaint = new Paint();
mPaint.setAntiAlias(true);
if (needRotate) {
rotate = (int) (Math.random() * 3) * 90;
} else {
rotate = 0;
}
}
/**
* 隨機生成生成滑塊的XY座標
*/
private void initUnitXY() {
mUnitRandomX = (int) (Math.random() * (mBitmap.getWidth() - mUintWidth));
mUnitRandomY = (int) (Math.random() * (mBitmap.getHeight() - mUintHeight));
// 防止生成的位置距離太近
if (mUnitRandomX <= mBitmap.getWidth() / 2) {
mUnitRandomX = mUnitRandomX + mBitmap.getWidth() / 4;
}
// 防止生成的X座標截圖時導致異常
if (mUnitRandomX + mUintWidth > getWidth()) {
initUnitXY();
return;
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (isReSet) {
mBitmap = getBaseBitmap();
if (0 == mUintWidth) {
mUintWidth = mBitmap.getWidth() / mUnitWidthScale;
}
if (0 == mUintHeight) {
mUintHeight = mBitmap.getHeight() / mUnitHeightScale;
}
initUnitXY();
mUnitBp = Bitmap.createBitmap(mBitmap, mUnitRandomX, mUnitRandomY, mUintWidth, mUintHeight);
}
isReSet = false;
canvas.drawBitmap(drawTargetBitmap(), mUnitRandomX, mUnitRandomY, mPaint);
canvas.drawBitmap(drawResultBitmap(mUnitBp), mUnitMoveDistance, mUnitRandomY, mPaint);
}
/**
* 重置
*/
public void reSet() {
isReSet = true;
mUnitMoveDistance = 0;
if (needRotate) {
rotate = (int) (Math.random() * 3) * 90;
} else {
rotate = 0;
}
invalidate();
}
/**
* 獲取每次滑動的平均偏移值
*
* @return
*/
public float getAverageDistance(int max) {
return (float) (mBitmap.getWidth() - mUintWidth) / max;
}
/**
* 滑塊移動距離
*
* @param distance
*/
public void setUnitMoveDistance(float distance) {
mUnitMoveDistance = distance;
// 防止滑塊滑出圖片
if (mUnitMoveDistance > mBitmap.getWidth() - mUintWidth) {
mUnitMoveDistance = mBitmap.getWidth() - mUintWidth;
}
invalidate();
}
/**
* 驗證是否拼接成功
*/
public void testPuzzle() {
if (Math.abs(mUnitMoveDistance - mUnitRandomX) <= DEFAULT_DEVIATE) {
if (null != mlistener) {
mlistener.onSuccess();
}
} else {
if (null != mlistener) {
mlistener.onFail();
}
}
}
/**
* 創建遮擋的圖片(陰影部分)
*
* @return
*/
private Bitmap drawTargetBitmap() {
// 繪製圖片
Bitmap showB;
if (null != mShowBp) {
showB = handleBitmap(mShowBp, mUintWidth, mUintHeight);
} else {
showB = handleBitmap(BitmapFactory.decodeResource(getResources(), R.mipmap.puzzle_show), mUintWidth, mUintHeight);
}
// 如果需要旋轉圖片,進行旋轉,旋轉後爲了保持和滑塊大小一致,需要重新縮放比例
if (needRotate) {
showB = handleBitmap(rotateBitmap(rotate, showB), mUintWidth, mUintHeight);
}
return showB;
}
/**
* 創建結合的圖片(滑塊)
*
* @param bp
*/
private Bitmap drawResultBitmap(Bitmap bp) {
// 繪製圖片
Bitmap shadeB;
if (null != mShadeBp) {
shadeB = handleBitmap(mShadeBp, mUintWidth, mUintHeight);
} else {
shadeB = handleBitmap(BitmapFactory.decodeResource(getResources(), R.mipmap.puzzle_shade), mUintWidth, mUintHeight);
}
// 如果需要旋轉圖片,進行旋轉,旋轉後爲了和畫布大小保持一致,避免出現圖像顯示不全,需要重新縮放比例
if (needRotate) {
shadeB = handleBitmap(rotateBitmap(rotate, shadeB), mUintWidth, mUintHeight);
}
Bitmap resultBmp = Bitmap.createBitmap(mUintWidth, mUintHeight,
Bitmap.Config.ARGB_8888);
Paint paint = new Paint();
paint.setAntiAlias(true);
Canvas canvas = new Canvas(resultBmp);
canvas.drawBitmap(shadeB, new Rect(0, 0, mUintWidth, mUintHeight),
new Rect(0, 0, mUintWidth, mUintHeight), paint);
// 選擇交集去上層圖片
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
canvas.drawBitmap(bp, new Rect(0, 0, mUintWidth, mUintHeight),
new Rect(0, 0, mUintWidth, mUintHeight), paint);
return resultBmp;
}
/**
* 獲取實際顯示的圖片
*
* @return
*/
public Bitmap getBaseBitmap() {
Bitmap b = drawableToBitamp(getDrawable());
float scaleX = 1.0f;
float scaleY = 1.0f;
// 如果圖片的寬或者高與view的寬高不匹配,計算出需要縮放的比例;縮放後的圖片的寬高,一定要大於我們view的寬高;所以我們這裏取大值;
scaleX = getWidth() * 1.0f / b.getWidth();
scaleY = getHeight() * 1.0f / b.getHeight();
Matrix matrix = new Matrix();
matrix.setScale(scaleX, scaleY);
Bitmap bd = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(),
matrix, true);
return bd;
}
/**
* drawable轉bitmap
*
* @param drawable
* @return
*/
private Bitmap drawableToBitamp(Drawable drawable) {
if (null == drawable) {
return null;
}
if (drawable instanceof BitmapDrawable) {
BitmapDrawable bd = (BitmapDrawable) drawable;
return bd.getBitmap();
}
int w = drawable.getIntrinsicWidth();
int h = 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;
}
/**
* 縮放圖片
*
* @param bp
* @param x
* @param y
* @return
*/
public static Bitmap handleBitmap(Bitmap bp, float x, float y) {
int w = bp.getWidth();
int h = bp.getHeight();
float sx = (float) x / w;
float sy = (float) y / h;
Matrix matrix = new Matrix();
matrix.postScale(sx, sy);
Bitmap resizeBmp = Bitmap.createBitmap(bp, 0, 0, w,
h, matrix, true);
return resizeBmp;
}
/**
* 旋轉圖片
*
* @param degree
* @param bitmap
* @return
*/
public Bitmap rotateBitmap(int degree, Bitmap bitmap) {
Matrix matrix = new Matrix();
matrix.postRotate(degree);
Bitmap bm = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
bitmap.getHeight(), matrix, true);
return bm;
}
}
MainActivity:
package com.example.junweiliu.douyutest;
import android.app.Activity;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.SeekBar;
import android.widget.Toast;
public class MainActivity extends Activity {
/**
* 滑塊
*/
private SeekBar mSeekBar;
/**
* 自定義的控件
*/
private DouYuView mDY;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
mDY = (DouYuView) findViewById(R.id.dy_v);
mSeekBar = (SeekBar) findViewById(R.id.sb_dy);
mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
// Log.e("main", "當前位置" + i);
mDY.setUnitMoveDistance(mDY.getAverageDistance(seekBar.getMax()) * i);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
mDY.testPuzzle();
}
});
mDY.setPuzzleListener(new DouYuView.onPuzzleListener() {
@Override
public void onSuccess() {
// mSeekBar.setEnabled(false);
Toast.makeText(MainActivity.this, "驗證成功", Toast.LENGTH_SHORT).show();
mSeekBar.setProgress(0);
mDY.reSet();
}
@Override
public void onFail() {
Toast.makeText(MainActivity.this, "驗證失敗", Toast.LENGTH_SHORT).show();
mSeekBar.setProgress(0);
}
});
}
}
xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:dy="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.junweiliu.douyutest.MainActivity">
<com.example.junweiliu.douyutest.DouYuView
android:id="@+id/dy_v"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:src="@mipmap/test"
dy:unitHeight="60dp"
dy:unitWidth="80dp"
dy:unitShowSrc="@mipmap/star_show"
dy:unitShadeSrc="@mipmap/star_shade"
dy:needRotate="true" />
<SeekBar
android:id="@+id/sb_dy"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="100" />
</LinearLayout>
實現的效果圖如下: