3D画廊
3D畫廊
之前我都是寫的學習的內容,我在寫這些教程時遇到有趣的炫酷的小例子也會專門拿出來寫一篇文章,今天就寫一個酷炫的小例子,叫3D畫廊,它是屬于ViewPage的進階版。
此項目下載地點:https://github.com/qySvip/3D-gallery
下面的指示器是使用的一大神的第三方庫,會在文章下方簡單講述一下。
效果圖
3D畫廊的實現
首先是布局文件
1 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 android:layout_width="match_parent" 3 android:layout_height="match_parent" 4 xmlns:app="http://schemas.android.com/apk/res-auto" 5 android:clipChildren="false" 6 android:background="@android:color/black" 7 android:id="@+id/frame_layout"> 8 9 <android.support.v4.view.ViewPager 10 android:layout_width="match_parent" 11 android:layout_height="450dp" 12 android:layout_gravity="center" 13 android:id="@+id/gallery" 14 android:clipChildren="false" 15 android:layout_marginLeft="85dp" 16 android:layout_marginRight="85dp" /> 17 18 <com.lwj.widget.viewpagerindicator.ViewPagerIndicator 19 android:id="@+id/indicator_circle_line" 20 android:layout_width="match_parent" 21 android:layout_height="50dp" 22 android:layout_gravity="bottom" 23 android:background="#efefef" 24 app:vpi_default_color="#FF239AF5" 25 app:vpi_distance="60dp" 26 app:vpi_distanceType="BY_LAYOUT" 27 app:vpi_indicatorType="CIRCLE_LINE" 28 app:vpi_radius="10dp" 29 app:vpi_selected_color="#FF239AF5" 30 /> 31 32 </FrameLayout>
代碼中的ViewPagerIndicator是用于實現下方的指示器,這個我們在最后在進行解釋;
首先布局使用幀布局,內部用到ViewPager控件,注意在ViewPager控件的父布局中我們要添加android:clipChildren="false"屬性,它的作用是定義它的子控件是否要在它應有的邊界內進行繪制,默認值為true。我們這里要用false。
然后在ViewPager中用到android:layout_marginLeft和android:layout_marginRight屬性,值不能太大,過大會導致看不到兩邊的圖像,具體根據自己滿意進行調整。高度屬性為圖片和倒影的加起來的高度,自己進行調整。
GalleryPageTransformer類
1 package sample.sdk.qy.com.demo;
2
3 import android.support.v4.view.ViewPager;
4 import android.view.View;
5
6 public class GalleryPageTransformer implements ViewPager.PageTransformer {
7 private static final float MAX_ROTATION=20.0f;
8 private static final float MIN_SCALE=0.75f;
9 private static final float MAX_TRANSLATE=20.0f;
10
11 @Override
12 public void transformPage(View page, float position) {
13 if(position<-1) {
14 page.setTranslationX(MAX_TRANSLATE);
15 page.setScaleX(MIN_SCALE);
16 page.setScaleY(MIN_SCALE);
17 page.setRotationY(-MAX_ROTATION);
18 }
19 else if(position<=0) {
20 page.setTranslationX(-MAX_TRANSLATE*position);
21 float scale=MIN_SCALE+(1-MIN_SCALE)*(1.0f+position);
22 page.setScaleX(scale);
23 page.setScaleY(scale);
24 page.setRotationY(MAX_ROTATION*position);
25 }
26 else if(position<=1) {
27 page.setTranslationX(-MAX_TRANSLATE*position);
28 float scale=MIN_SCALE+(1-MIN_SCALE)*(1.0f-position);
29 page.setScaleX(scale);
30 page.setScaleY(scale);
31 page.setRotationY(MAX_ROTATION*position);
32 }
33 else {
34 page.setTranslationX(-MAX_TRANSLATE);
35 page.setScaleX(MIN_SCALE);
36 page.setScaleY(MIN_SCALE);
37 page.setRotationY(MAX_ROTATION);
38 }
39 }
40 }
PageTransformer是ViewPager內部定義的接口,這個接口主要用于控制ViewPager中item view的滑動效果。
setTranslationX 設置view相對原始位置的水平偏移量
setScaleX 設置水平縮放的基準點
setScaleY 設置豎直縮放的基準點
setRotationY 設置豎直的選擇的基準點
ImageUtils類
1 package sample.sdk.qy.com.demo;
2
3 import android.content.Context;
4 import android.graphics.Bitmap;
5 import android.graphics.BitmapFactory;
6 import android.graphics.Canvas;
7 import android.graphics.Color;
8 import android.graphics.LinearGradient;
9 import android.graphics.Matrix;
10 import android.graphics.Paint;
11 import android.graphics.PorterDuff;
12 import android.graphics.PorterDuffXfermode;
13 import android.graphics.Shader;
14
15 public class ImageUtils {
16 public static Bitmap getReverseBitmapById(Context context, int resId, float percent) {
17 // get the source bitmap
18 Bitmap srcBitmap= BitmapFactory.decodeResource(context.getResources(), resId);
19 // get the tow third segment of the reverse bitmap
20 Matrix matrix=new Matrix();
21 matrix.setScale(1, -1);
22 Bitmap rvsBitmap=Bitmap.createBitmap(srcBitmap, 0, (int) (srcBitmap.getHeight()*(1-percent)),
23 srcBitmap.getWidth(), (int) (srcBitmap.getHeight()*percent), matrix, false);
24 // combine the source bitmap and the reverse bitmap
25 Bitmap comBitmap=Bitmap.createBitmap(srcBitmap.getWidth(),
26 srcBitmap.getHeight()+rvsBitmap.getHeight()+20, srcBitmap.getConfig());
27 Canvas gCanvas=new Canvas(comBitmap);
28 gCanvas.drawBitmap(srcBitmap, 0, 0, null);
29 gCanvas.drawBitmap(rvsBitmap, 0, srcBitmap.getHeight()+20, null);
30 Paint paint=new Paint();
31 LinearGradient shader=new LinearGradient(0, srcBitmap.getHeight()+20, 0, comBitmap.getHeight(),
32 Color.BLACK, Color.TRANSPARENT, Shader.TileMode.CLAMP);
33 paint.setShader(shader);
34 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
35 gCanvas.drawRect(0, srcBitmap.getHeight()+20, srcBitmap.getWidth(), comBitmap.getHeight(), paint);
36 return comBitmap;
37 }
38 }
這是做圖片倒影的方法,內部使用了Canvas和Bitmap類,這些后面會進行講述。
ViewAdapter類
1 package sample.sdk.qy.com.demo;
2
3 import android.support.v4.view.PagerAdapter;
4 import android.view.View;
5 import android.view.ViewGroup;
6
7 import java.util.List;
8
9 public class ViewAdapter extends PagerAdapter {
10 private List<View> datas;
11
12 public ViewAdapter(List<View> list) {
13 datas=list;
14 }
15
16 @Override
17 public int getCount() {
18 return datas.size();
19 }
20
21 @Override
22 public boolean isViewFromObject(View view, Object object) {
23 return view==object;
24 }
25
26 @Override
27 public Object instantiateItem(ViewGroup container, int position) {
28 View view=datas.get(position);
29 container.addView(view);
30 return view;
31 }
32
33 @Override
34 public void destroyItem(ViewGroup container, int position, Object object) {
35 container.removeView(datas.get(position));
36 }
37 }
適配器類,這里的適配方式為圖片和倒影一同進行適配。
MainActivity類
1 package sample.sdk.qy.com.demo;
2
3 import android.app.Activity;
4 import android.os.Bundle;
5 import android.support.v4.view.PagerAdapter;
6 import android.support.v4.view.ViewPager;
7 import android.view.MotionEvent;
8 import android.view.View;
9 import android.widget.FrameLayout;
10 import android.widget.ImageView;
11
12 import com.lwj.widget.viewpagerindicator.ViewPagerIndicator;
13
14 import java.lang.reflect.Field;
15 import java.util.ArrayList;
16 import java.util.List;
17
18 public class MainActivity extends Activity {
19
20 private List<View> pages;
21 private FrameLayout layout;
22 private ViewPager pager;
23 private ViewPagerIndicator mIndicatorCircleLine;
24
25 @Override
26 protected void onCreate(Bundle savedInstanceState) {
27 super.onCreate(savedInstanceState);
28 setContentView(R.layout.activity_main);
29
30 pages=getPages();
31 pager=(ViewPager) findViewById(R.id.gallery);
32 PagerAdapter adapter=new ViewAdapter(pages);
33 pager.setAdapter(adapter);
34 pager.setPageMargin(20);
35 pager.setOffscreenPageLimit(3);
36 pager.setPageTransformer(true, new GalleryPageTransformer());
37
38 layout=(FrameLayout) findViewById(R.id.frame_layout);
39 layout.setOnTouchListener(new View.OnTouchListener() {
40 @Override
41 public boolean onTouch(View v, MotionEvent event) {
42 return pager.dispatchTouchEvent(event);
43 }
44 });
45
46 mIndicatorCircleLine = (ViewPagerIndicator) findViewById(R.id.indicator_circle_line);
47 mIndicatorCircleLine.setViewPager(pager,9);
48 }
49
50 private List<View> getPages() {
51 List<View> pages=new ArrayList<>();
52 Field[] fields=R.drawable.class.getDeclaredFields();
53 try {
54 for (Field field : fields) {
55 if (field.getName().startsWith("page")) {
56 ImageView view = new ImageView(this);
57 view.setImageBitmap(ImageUtils.getReverseBitmapById(this, field.getInt(null), 0.5f));
58 pages.add(view);
59 }
60 }
61 } catch (IllegalAccessException e) {
62 e.printStackTrace();
63 }
64 return pages;
65 }
66 }
主界面方法,主要用于填充入圖片、適配器適配。這里填充圖片的方法為在drawable文件中查找以page開頭的圖片進行填充。
到這里3D畫廊就完成了。。。。。。。。。
指示器
下面來說一下指示器的做法,用的是網上一大神的第三方類。
使用方法:
1、在 project的build.gradle 添加:
allprojects { repositories { ... maven { url "https://jitpack.io" } } }
2、在module的build.gradle 添加:
dependencies {implementation'com.github.LinweiJ:ViewPagerIndicator:0.1.0' }
注意這里要用implementation,compile現在已被廢棄,官方顯示將在2018年年底刪除。
3、將ViewPagerIndicator控件添加到布局文件。
屬性:
app:vpi_selected_color
app:vpi_default_color(如果 indicatorType=CIRCLE_LINE default_color 為指示器唯一顏色 ,selected_color 不起作用)
app:vpi_radius(點的大小,在indicatorType= CIRCLE_LINE 的情況下 radius 是點的高)
app:vpi_length(只作用在 indicatorType=CIRCLE_LINE 的情況下,為 指示器點的長度)
app:vpi_distance(只作用在 distanceType=BY_DISTANCE 的情況下)
app:vpi_num
app:vpi_indicatorType(LINE; CIRCLE; CIRCLE_LINE; BEZIER;SPRING)LINE:線 ; CIRCLE:圓點(默認) ; CIRCLE_LINE:圓角矩形; BEZIER:彈性球 ; SPRING: 彈簧粘性球
app:vpi_distanceType(BY_RADIUS; BY_DISTANCE ; BY_LAYOUT )BY_RADIUS:3倍radius ; BY_DISTANCE :定義固定距離 ;BY_LAYOUT :根據layout_width均分得到距離
app:vpi_animation(默認為true:動畫開啟 ; false:關閉動畫)
4、在java文件中初始化該控件
使用mIndicatorCircleLine.setViewPager(pager,9);,第一個參數為適配器,第二個參數為圖片的個數。
總結
- 上一篇: Xenserver命令大全
- 下一篇: Android测试(四):Instrum