android ViewPager 仿畫廊/圖書翻頁 與 palette 使用
- 普通ViewPager實作
- ViewPager.PageTransformer
- 仿圖書效果
- palette 調色闆
廢話不多說,先來看看完成的效果!
總結實作效果:
- ViewPager 實作無限自動播放
- ViewPager 實作中間大,兩邊小 [仿畫廊效果]
- ViewPager 實作圖檔疊加[仿圖書翻頁效果]
- palette 調色闆實作識别圖檔顔色,随着圖檔的變化來改變背景色的變化
普通ViewPager實作
先不管三七二十一,先吧最基本的ViewPager實作,之後在在基本的ViewPager上修改!
不用複制代碼,先看思路就行,底部會給出完整代碼!
activity_palette.xml布局:
java代碼:
//設定擴充卡
viewPager.setAdapter(new BannerAdapter(this, mDrawables));
//Pager之間的間距
viewPager.setPageMargin(20);
//預加載
viewPager.setOffscreenPageLimit(3);
//預設第一張圖 左右都有圖
viewPager.setCurrentItem(1);
BannerAdapter 擴充卡:
public class BannerAdapter extends PagerAdapter {
private int[] mData;
private Context mContext;
public BannerAdapter(Context ctx, int[] data) {
this.mContext = ctx;
this.mData = data;
}
@Override
public int getCount() {
return mData.length;// 傳回資料的個數
}
@Override
public Object instantiateItem(final ViewGroup container, final int position) {//子View顯示
View view = View.inflate(container.getContext(), R.layout.banner_item_layout, null);
ImageView imageView = view.findViewById(R.id.iv_icon);
imageView.setImageResource(mData[position]);
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(mContext, "目前條目:" + position, Toast.LENGTH_SHORT).show();
}
});
container.addView(view);//添加到父控件
return view;
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;// 過濾和緩存的作用
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);//從viewpager中移除掉
}
}
先來看看目前的效果:
就是一個很簡單的ViewPager沒什麼好說的!
思路分析:
要想完成畫廊的效果,那麼必須吧viewPager分為以下幾步驟:
- 讓ViewPager顯示出左右兩側的View
- 無限滑動
- 自定義ViewPager 滑動動畫,滑動過程中中間大,兩邊小
- 自動播放
那就來根據思路實作效果吧 :
讓ViewPager顯示出左右兩側的View
來看看效果:
無限滑動
這個也是真 的簡單,直接取%即可實作
來看看效果:
中間大,兩邊小效果
要想實作這個效果,就要來介紹本篇重中之重! ViewPager.PageTransformer
ViewPager.PageTransformer
先來看使用:
- 參數一: 是否逆轉,我沒看出有什麼效果,懂這個參數的記得在評論區留言哦!
- 參數二: 用來控制ViewPager 動畫的
public class ScaleTransformer implements ViewPager.PageTransformer {
private static final float MAX_SCALE = 1.0f;//0縮放
private static final float MIN_SCALE = 0.80f;//0.85縮放
@Override
public void transformPage(@NonNull View view, float position) {
}
}
實作implements ViewPager.PageTransformer重寫transformPage()方法,有2個參數
/**
* A PageTransformer is invoked whenever a visible/attached page is scrolled.
* This offers an opportunity for the application to apply a custom transformation
* to the page views using animation properties.
*
* <p>As property animation is only supported as of Android 3.0 and forward,
* setting a PageTransformer on a ViewPager on earlier platform versions will
* be ignored.</p>
*/
public interface PageTransformer {
/**
* Apply a property transformation to the given page.
*
* @param page Apply the transformation to this page
* @param position Position of page relative to the current front-and-center
* position of the pager. 0 is front and center. 1 is one full
* page position to the right, and -1 is one page position to the left.
*/
void transformPage(@NonNull View page, float position);
}
這個方法在onPageScrolled頁面滑動的過程中回調
@CallSuper
protected void onPageScrolled(int position, float offset, int offsetPixels) {
....省略.......
if (mPageTransformer != null) {
....省略.......
mPageTransformer.transformPage(child, transformPos);
}
}
mCalledSuper = true;
}
transformPage參數:
- 參數一: 目前view
- 參數二:目前view的位置
這裡比較抽象,畫張圖看看
- 紅色目前View
- 藍色 左側View
- 黃色 右側View
不滑動狀态position變化:
紅色 | 藍色 | 黃色 |
---|---|---|
position = -1 | position = 0 | position = 1 |
滑動狀态position變化:
狀态 | 紅色 | 藍色 | 黃色 |
---|---|---|---|
左滑動 | position < -1 | 0 < position < -1 | 1 < position < 0 |
右滑動 | -1 < position < 0 | 0 < position < 1 | position > 1 |
先來列印一下看看position的值:
還看不懂? 再來畫一張圖:
好了,position就介紹到這裡!
先簡簡單單修改代碼,先看看效果:
public class ScaleTransformer implements ViewPager.PageTransformer {
private static final float MAX_SCALE = 1.0f;//0縮放
private static final float MIN_SCALE = 0.80f;//0.85縮放
@Override
public void transformPage(@NonNull View view, float position) {
//position != 0 表示左側和右側的view
if (position != 0) {
view.setScaleX(MIN_SCALE);
view.setScaleY(MIN_SCALE);
} else {
view.setScaleX(MAX_SCALE);
view.setScaleY(MAX_SCALE);
}
}
}
效果:
可以看到,要實作的效果已經漸漸接近了!
在加上滑動時候放大縮小即可
public class ScaleTransformer implements ViewPager.PageTransformer {
private static final float MAX_SCALE = 1.0f;//0縮放
private static final float MIN_SCALE = 0.80f;//0.85縮放
@Override
public void transformPage(@NonNull View view, float position) {
if (position < 1) {
float scaleFactor = MIN_SCALE + (1 - Math.abs(position)) * (MAX_SCALE - MIN_SCALE);
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
} else {
view.setScaleX(MIN_SCALE);
view.setScaleY(MIN_SCALE);
}
}
}
這裡涉及到一個小算法
指的就是變化過程中view的大小
這段代碼要細細的品味一下!!!很關鍵!!
來看看濕滑的效果:
無限自己滾動
這段代碼也是簡單的很:
直接上代碼不多貝貝:
//用來記錄是否按壓,如果按壓,則不滾動
boolean isDown ;
Timer timer = new Timer();
//定時器播放ViewPager
TimerTask timerTask = new TimerTask() {
@Override
public void run() {
if (!isDown) {
//擷取到目前的位置
int page = viewPager.getCurrentItem() + 1;
runOnUiThread(() -> viewPager.setCurrentItem(page));
}
}
};
// 每2.5秒執行一次
timer.schedule(timerTask, 0, 2500);
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
//viewPager滑動的時候,設定不讓滾動
isDown = true;
}
@Override
public void onPageSelected(int position) {
}
@Override
public void onPageScrollStateChanged(int state) {
//ViewPager不點選了讓滾動
isDown = false;
}
});
這段代碼過于簡單,就不看效果了!
仿圖書效果
這個效果和仿畫廊流程一樣,也是對PageTransformer的操作,直接上代碼了!
public class StackPageTransformer implements ViewPager.PageTransformer {
private final ViewPager viewPager;
private final float SCALE_VALUE = 1f;
//View 之間的偏移量
private final float DEVIATION = 60f;
//旋轉
private final float ROTATION = 60f;
//圖檔是否疊加【預設不疊加】
private final boolean isStack = false;
public StackPageTransformer(ViewPager viewPager) {
this.viewPager = viewPager;
}
@Override
public void transformPage(@NonNull View view, float position) {
Log.i("szjPosition2", position + "");
/*
* 當不滑動狀态下:
* position = -1 左側View
* position = 0 目前View
* position = 1 右側View
*
* 當滑動狀态下:
* 向左滑動: [ position < 0 && position > -1]
* 左側View position < -1
* 目前View 0 ~ -1
* 右側View 1 ~ 0
*
* 向右滑動:[position > 0 && position < 1 ]
* 左側View -1 < position < 0
* 目前View 0 ~ 1
* 右側View position > 1
*/
int pageWidth = viewPager.getWidth();
//隐藏左側側的view
if (position == -1) {
view.setVisibility(View.GONE);
} else {
view.setVisibility(View.VISIBLE);
}
//目前View和右側的View [讓右側View和目前View疊加起來]
if (position >= 0) {
float translationX;
//這裡不要暈! 改變isStack來看看效果吧!!
if (isStack) {
translationX = DEVIATION - (pageWidth) * position;
} else {
translationX = (DEVIATION - pageWidth) * position;
}
Log.i("szjTranslationX", translationX + "");
view.setTranslationX(translationX);
}
//目前view
if (position == 0) {
view.setScaleX(SCALE_VALUE);
view.setScaleY(SCALE_VALUE);
} else {
//左側已經隐藏了,是以這裡值的是右側View的偏移量
float scaleFactor = Math.min(SCALE_VALUE - position * 0.1f, SCALE_VALUE);
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
}
//向左滑動
if (position < 0 && position > -1) {
//旋轉
view.setRotation(ROTATION * position);
view.setAlpha(1 - Math.abs(position));
} else {
//透明度 其他狀态不設定透明度
view.setAlpha(1);
}
//向右滑動
if (position > 0 && position < 1) {
view.setRotation(0);
}
}
}
看看效果:
palette 調色闆
先添加依賴:
簡單介紹:
palette 傳入一張Bitmap,然後他會通過圖檔像素點來分析出顔色占比,提取出你需要的顔色!!
使用:
public void initPalette(Bitmap bitmap) {
new Thread(() -> Palette.from(bitmap).generate(palette -> {
//以RGB壓縮整數的形式從調色闆傳回靜音和深色。
int darkMutedColor = palette.getDarkMutedColor(Color.TRANSPARENT);
//暗 柔和 [以RGB壓縮整數的形式從調色闆傳回靜音和淺色。]
int lightMutedColor = palette.getLightMutedColor(Color.TRANSPARENT);
//暗 鮮豔 [以RGB壓縮整數的形式從調色闆傳回深色和鮮豔的顔色。]
int darkVibrantColor = palette.getDarkVibrantColor(Color.TRANSPARENT);
//量 鮮豔 [以RGB壓縮整數的形式從調色闆傳回明亮的顔色。]
int lightVibrantColor = palette.getLightVibrantColor(Color.TRANSPARENT);
//柔和 [将調色闆中的靜音顔色作為RGB壓縮整數傳回。]
int mutedColor = palette.getMutedColor(Color.TRANSPARENT);
//以RGB壓縮整數形式傳回調色闆中最鮮豔的顔色。
int vibrantColor = palette.getVibrantColor(Color.TRANSPARENT);
//從調色闆中傳回一個明亮且充滿活力的樣例。可能為空。
Palette.Swatch lightVibrantSwatch = palette.getLightVibrantSwatch();
int hotColor = Color.TRANSPARENT;
if (lightVibrantSwatch != null) {
//谷歌推薦的:圖檔的整體的顔色rgb的混合痔---主色調
int rgb = lightVibrantSwatch.getRgb();
hotColor = getTranslucentColor(0.7f, rgb);
}
// 拿到顔色 這裡就可以給View 設定顔色了
})).start();
}
然後通過随機圖檔,設定不同的圖檔來測試一下管用不管用!
來看看效果:
這裡用到了動态代碼設定漸變,代碼很簡單,給大家看看吧
/**
* TODO 設定漸變顔色
*
* @param view 需要設定的View
* @param colors 漸變顔色
* @param type 漸變位置 例如:GradientDrawable.Orientation.LEFT_RIGHT 從左到右
* @param radius 圓角
*/
public void setGradualChange(View view, int[] colors, GradientDrawable.Orientation type, int radius) {
GradientDrawable drawable = new GradientDrawable(type, colors);
drawable.setCornerRadius(radius);
view.setBackground(drawable);
}
完整項目
原創不易,您的點贊就是對我最大的支援!!