Android實例(一)—— 3D畫廊

3D畫廊java

以前我都是寫的學習的內容,我在寫這些教程時遇到有趣的炫酷的小例子也會專門拿出來寫一篇文章,今天就寫一個酷炫的小例子,叫3D畫廊,它是屬於ViewPage的進階版。android

此項目下載地點:github.com/qySvip/3D-g…git

下面的指示器是使用的一大神的第三方庫,會在文章下方簡單講述一下。github

效果圖面試

image

3D畫廊的實現性能優化

首先是佈局文件bash

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:clipChildren="false"
    android:background="@android:color/black"
    android:id="@+id/frame_layout">

    <android.support.v4.view.ViewPager
        android:layout_width="match_parent"
        android:layout_height="450dp"
        android:layout_gravity="center"
        android:id="@+id/gallery"
        android:clipChildren="false"
        android:layout_marginLeft="85dp"
        android:layout_marginRight="85dp" />

        <com.lwj.widget.viewpagerindicator.ViewPagerIndicator
            android:id="@+id/indicator_circle_line"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:layout_gravity="bottom"
            android:background="#efefef"
            app:vpi_default_color="#FF239AF5"
            app:vpi_distance="60dp"
            app:vpi_distanceType="BY_LAYOUT"
            app:vpi_indicatorType="CIRCLE_LINE"
            app:vpi_radius="10dp"
            app:vpi_selected_color="#FF239AF5"
            />

</FrameLayout>
複製代碼

代碼中的ViewPagerIndicator是用於實現下方的指示器,這個咱們在最後在進行解釋;架構

首先佈局使用幀佈局,內部用到ViewPager控件,注意在ViewPager控件的父佈局中咱們要添加android:clipChildren="false"屬性,它的做用是定義它的子控件是否要在它應有的邊界內進行繪製,默認值爲true。咱們這裏要用false。app

而後在ViewPager中用到android:layout_marginLeft和android:layout_marginRight屬性,值不能太大,過大會致使看不到兩邊的圖像,具體根據本身滿意進行調整。高度屬性爲圖片和倒影的加起來的高度,本身進行調整。maven

GalleryPageTransformer類

package sample.sdk.qy.com.demo;

import android.support.v4.view.ViewPager;
import android.view.View;

public class GalleryPageTransformer implements ViewPager.PageTransformer {
    private static final float MAX_ROTATION=20.0f;
    private static final float MIN_SCALE=0.75f;
    private static final float MAX_TRANSLATE=20.0f;

    @Override
    public void transformPage(View page, float position) {
        if(position<-1) {
            page.setTranslationX(MAX_TRANSLATE);
            page.setScaleX(MIN_SCALE);
            page.setScaleY(MIN_SCALE);
            page.setRotationY(-MAX_ROTATION);
        }
        else if(position<=0) {
            page.setTranslationX(-MAX_TRANSLATE*position);
            float scale=MIN_SCALE+(1-MIN_SCALE)*(1.0f+position);
            page.setScaleX(scale);
            page.setScaleY(scale);
            page.setRotationY(MAX_ROTATION*position);
        }
        else if(position<=1) {
            page.setTranslationX(-MAX_TRANSLATE*position);
            float scale=MIN_SCALE+(1-MIN_SCALE)*(1.0f-position);
            page.setScaleX(scale);
            page.setScaleY(scale);
            page.setRotationY(MAX_ROTATION*position);
        }
        else {
            page.setTranslationX(-MAX_TRANSLATE);
            page.setScaleX(MIN_SCALE);
            page.setScaleY(MIN_SCALE);
            page.setRotationY(MAX_ROTATION);
        }
    }
}
複製代碼

PageTransformer是ViewPager內部定義的接口,這個接口主要用於控制ViewPager中item view的滑動效果。

  • setTranslationX 設置view相對原始位置的水平偏移量
  • setScaleX 設置水平縮放的基準點
  • setScaleY 設置豎直縮放的基準點
  • setRotationY 設置豎直的選擇的基準點

ImageUtils類

package sample.sdk.qy.com.demo;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Shader;

public class ImageUtils {
    public static Bitmap getReverseBitmapById(Context context, int resId, float percent) {
        // get the source bitmap
        Bitmap srcBitmap= BitmapFactory.decodeResource(context.getResources(), resId);
        // get the tow third segment of the reverse bitmap
        Matrix matrix=new Matrix();
        matrix.setScale(1, -1);
        Bitmap rvsBitmap=Bitmap.createBitmap(srcBitmap, 0, (int) (srcBitmap.getHeight()*(1-percent)),
                srcBitmap.getWidth(), (int) (srcBitmap.getHeight()*percent), matrix, false);
        // combine the source bitmap and the reverse bitmap
        Bitmap comBitmap=Bitmap.createBitmap(srcBitmap.getWidth(),
                srcBitmap.getHeight()+rvsBitmap.getHeight()+20, srcBitmap.getConfig());
        Canvas gCanvas=new Canvas(comBitmap);
        gCanvas.drawBitmap(srcBitmap, 0, 0, null);
        gCanvas.drawBitmap(rvsBitmap, 0, srcBitmap.getHeight()+20, null);
        Paint paint=new Paint();
        LinearGradient shader=new LinearGradient(0, srcBitmap.getHeight()+20, 0, comBitmap.getHeight(),
                Color.BLACK, Color.TRANSPARENT, Shader.TileMode.CLAMP);
        paint.setShader(shader);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
        gCanvas.drawRect(0, srcBitmap.getHeight()+20, srcBitmap.getWidth(), comBitmap.getHeight(), paint);
        return comBitmap;
    }
}
複製代碼

這是作圖片倒影的方法,內部使用了Canvas和Bitmap類,這些後面會進行講述。

ViewAdapter類

package sample.sdk.qy.com.demo;

import android.support.v4.view.PagerAdapter;
import android.view.View;
import android.view.ViewGroup;

import java.util.List;

public class ViewAdapter extends PagerAdapter {
    private List<View> datas;

    public ViewAdapter(List<View> list) {
        datas=list;
    }

    @Override
    public int getCount() {
        return datas.size();
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view==object;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        View view=datas.get(position);
        container.addView(view);
        return view;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView(datas.get(position));
    }
}
複製代碼

適配器類,這裏的適配方式爲圖片和倒影一同進行適配。

MainActivity類

package sample.sdk.qy.com.demo;

import android.app.Activity;
import android.os.Bundle;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;

import com.lwj.widget.viewpagerindicator.ViewPagerIndicator;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends Activity {

    private List<View> pages;
    private FrameLayout layout;
    private ViewPager pager;
    private ViewPagerIndicator mIndicatorCircleLine;

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

        pages=getPages();
        pager=(ViewPager) findViewById(R.id.gallery);
        PagerAdapter adapter=new ViewAdapter(pages);
        pager.setAdapter(adapter);
        pager.setPageMargin(20);
        pager.setOffscreenPageLimit(3);
        pager.setPageTransformer(true, new GalleryPageTransformer());

        layout=(FrameLayout) findViewById(R.id.frame_layout);
        layout.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                return pager.dispatchTouchEvent(event);
            }
        });

        mIndicatorCircleLine = (ViewPagerIndicator) findViewById(R.id.indicator_circle_line);
        mIndicatorCircleLine.setViewPager(pager,9);
    }

    private List<View> getPages() {
        List<View> pages=new ArrayList<>();
        Field[] fields=R.drawable.class.getDeclaredFields();
        try {
            for (Field field : fields) {
                if (field.getName().startsWith("page")) {
                    ImageView view = new ImageView(this);
                    view.setImageBitmap(ImageUtils.getReverseBitmapById(this, field.getInt(null), 0.5f));
                    pages.add(view);
                }
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return pages;
    }
}
複製代碼

主界面方法,主要用於填充入圖片、適配器適配。這裏填充圖片的方法爲在drawable文件中查找以page開頭的圖片進行填充。

到這裏3D畫廊就完成了。。。。。。。。。

指示器

下面來講一下指示器的作法,用的是網上一大神的第三方類。

使用方法:

一、在 project的build.gradle 添加:

allprojects { repositories { ... maven { url "https://jitpack.io" } } }

二、在module的build.gradle 添加:

dependencies {implementation  'com.github.LinweiJ:ViewPagerIndicator:0.1.0' }

注意這裏要用implementation,compile如今已被廢棄,官方顯示將在2018年年末刪除。

三、將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:關閉動畫)

四、在java文件中初始化該控件

使用mIndicatorCircleLine.setViewPager(pager,9);,第一個參數爲適配器,第二個參數爲圖片的個數。

有興趣的能夠加羣交流技術【Android技術交流】:jq.qq.com/?_wv=1027&a…。進羣 免費領取安卓進階學習視頻,源碼,面試資料,羣內有大牛一塊兒交流討論技術;點擊連接加入羣聊(包括java基礎與原理,自定義控件、NDK、架構設計、混合式開發(Flutter,Weex)、性能優化、完整商業項目開發等)
相關文章
相關標籤/搜索