ViewPager---仿掌上英雄联盟皮肤浏览效果


ViewPager---仿掌上英雄联盟皮肤浏览效果 效果图:




源码地址:仿掌上英雄联盟皮肤浏览器-ViewPager
微信公众号:

思路与分析

在开始写代码之前,我们还是来分析一下界面元素,和该用什么技术来实现各个部分。

1,首先是整个界面的滑动,我们肯定一眼就能看出来,用ViewPager 实现。2,ViewPager 滑动时有放大缩小的动画,用ViewPager.Transfoemer 轻松搞定。3,ViewPager 显示多页(展示前后页面的部分)。4,界面图片的形状,旋转90度的等腰梯形。这个只能用自定义View来实现了。5,整个界面的背景为当前显示图片的高斯模糊图。

代码实现

上面分析了界面的构成元素,那么现在我们就来看一下具体的实现。

1, ViewPager 展示多页
这个问题在我们前一篇文章已经讲过,这里不再重复,就是用ViewGroup 的 clipChildren 属性,值为false。也就是在整个布局的跟节点添加下面一行代码:

          android:clipChildren="false"
然后,ViewPager需要设置左右Margin,也就是前后页显示的位置
                  
<android.support.v4.view.ViewPager
android:id="@+id/my_viewpager"
android:layout_width="wrap_content"
android:layout_height="300dp"
android:clipChildren="false"
android:layout_marginLeft="50dp"
android:layout_marginRight="50dp"
android:layout_centerInParent="true"
/>

好了,这样ViewPager就能显示多页,并且当前页和前后页之间还有一定的间距。

2, ViewPager 切换时的动画
ViewPager 切换时的自定义动画用ViewPager.PageTransformer, 这个在上一篇文章也讲过,没看过的倒回去看一下。这里不细讲了,直接上代码:

package demo.spdbank.hcq.com.viewpager_lol;

import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.View;

/**
* Created by zhouwei on 17/5/24.
*/

public class CustomViewPagerTransformer implements ViewPager.PageTransformer {
private int maxTranslateOffsetX;
private ViewPager viewPager;
private static final float MIN_SCALE = 0.75f;


public CustomViewPagerTransformer(Context context) {
this.maxTranslateOffsetX = dp2px(context, 160);
}

public void transformPage(View view, float position) {
// position的可能性的值有,其实从官方示例的注释就能看出:
//[-Infinity,-1) 已经看不到了
// (1,+Infinity] 已经看不到了
// [-1,1]
// 而我们从写PageTransformer,操作View动画的重点区间就在[-1,1]
Log.e("fuck","view:"+view+" position:"+position);
if (viewPager == null) {
viewPager = (ViewPager) view.getParent();
}
int leftInScreen = view.getLeft() - viewPager.getScrollX();
int centerXInViewPager = leftInScreen + view.getMeasuredWidth() / 2;
int offsetX = centerXInViewPager - viewPager.getMeasuredWidth() / 2;
float offsetRate = (float) offsetX * 0.38f / viewPager.getMeasuredWidth();
float scaleFactor = 1 - Math.abs(offsetRate);
if (scaleFactor > 0) {
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
view.setTranslationX(-maxTranslateOffsetX * offsetRate);
}

}

/**
* dp和像素转换
*/
private int dp2px(Context context, float dipValue) {
float m = context.getResources().getDisplayMetrics().density;
return (int) (dipValue * m + 0.5f);
}
}


3, 自定义多边形ImageView
多边形ImageView,我们通过自定义的方式实现,继承ImageView, 然后重写onDraw()方法。这里实现这种不规则的多边形View有两种方法。第一:使用PorterDuffXfermode,这种方法需要你给一个蒙板图片,在onDraw 方法中,先绘制蒙板图片,然后设置Paint的setXfermode 为PorterDuff.Mode.SRC_IN,再绘制要显示的图片,这样就能把显示的图片裁剪成蒙板的形状。第二: 使用canvas的clipPath() 方法,我们用Path 来绘制多边形,然后clipPath() 将画布裁剪成绘制的形状,然后在绘制要显示的图片。

关于PorterDuffXfermode 的更多用法,有兴趣的可以去google 一下,网上有很多相关的文章。这里我用的是两种方法的结合,先用clipPath得到一个需要形状的bitmap,然后使用PorterDuffXfermode。自定义View代码如下:

package demo.spdbank.hcq.com.viewpager_lol;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.support.annotation.DrawableRes;
import android.support.annotation.Nullable;
import android.support.v7.widget.AppCompatImageView;
import android.util.AttributeSet;
import android.view.View;

import com.zhouwei.indicatorview.DisplayUtils;

/**
* Created by zhouwei on 17/5/24.
*/

public class PolygonView extends AppCompatImageView {
private int mWidth = 0;
private int mHeight = 0;
private Paint mPaint;
private Paint mBorderPaint;
private PorterDuffXfermode mXfermode;
private Bitmap mBitmap;
private int mBorderWidth;
private Bitmap mMaskBitmap;
public PolygonView(Context context) {
super(context);
init();
}

public PolygonView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}

public PolygonView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}

private void init(){
mBorderWidth = DisplayUtils.dpToPx(4);
setLayerType(View.LAYER_TYPE_SOFTWARE, null);// 关闭硬件加速加速
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(Color.RED);
mPaint.setDither(true);

mBorderPaint = new Paint();
mBorderPaint.setColor(Color.WHITE);
mBorderPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mBorderPaint.setAntiAlias(true);//抗锯齿
mBorderPaint.setDither(true);//防抖动

mXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);

}


@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mWidth = getMeasuredWidth();
mHeight = getMeasuredHeight();

mMaskBitmap = getMaskBitmap();

}

@Override
public void setImageResource(@DrawableRes int resId) {
super.setImageResource(resId);
mBitmap = BitmapFactory.decodeResource(getResources(),resId);
invalidate();
}

@Override
protected void onDraw(Canvas canvas) {

canvas.save();

canvas.drawBitmap(mMaskBitmap,0,0,mBorderPaint);
mPaint.setXfermode(mXfermode);

Bitmap bitmap = getCenterCropBitmap(mBitmap,mWidth,mHeight);
canvas.drawBitmap(bitmap,0,0,mPaint);
mPaint.setXfermode(null);
canvas.restore();


}

private Bitmap getMaskBitmap(){
Bitmap bm = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bm);

Point point1 = new Point(0,30);
Point point2 = new Point(mWidth,0);
Point point3 = new Point(mWidth,mHeight);
Point point4 = new Point(0,mHeight - 30);

Path path = new Path();
path.moveTo(point1.x,point1.y);
path.lineTo(point2.x,point2.y);
path.lineTo(point3.x,point3.y);
path.lineTo(point4.x,point4.y);
path.close();

c.drawPath(path,mBorderPaint);

return bm;
}

private Bitmap getCenterCropBitmap(Bitmap src, float rectWidth, float rectHeight) {

float srcRatio = ((float) src.getWidth()) / src.getHeight();
float rectRadio = rectWidth / rectHeight;
if (srcRatio < rectRadio) {
return Bitmap.createScaledBitmap(src, (int)rectWidth, (int)((rectWidth / src.getWidth()) * src.getHeight()), false);
} else {
return Bitmap.createScaledBitmap(src, (int)((rectHeight / src.getHeight()) * src.getWidth()), (int)rectHeight, false);
}
}

/**
* 对原图进行等比裁剪
*/
private Bitmap scaleImage(Bitmap bitmap){

if(bitmap!=null){

int widht=bitmap.getWidth();
int height=bitmap.getHeight();

int new_width=0;
int new_height=0;

if(widht!=height){
if(widht>height){
new_height=mHeight;
new_width=widht*new_height/height;
}else{
new_width=mWidth;
new_height=height*new_width/widht;
}
}else{
new_width=mWidth;
new_height=mHeight;
}
return Bitmap.createScaledBitmap(bitmap, new_width, new_height, true);
}
return null;
}


}




4, 背景图高斯模糊
背景的高斯模糊就很简单了,关联了一个EasyBlur,只需要简单几行代码就行。我们在ViewPager的onPageSelect方法中,获取显示的图片,进行高斯模糊处理。

最后,给出完整的布局文件和Activity代码:
1, activity布局文件:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:clipChildren="false"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- 高斯模糊背景-->
<ImageView
android:id="@+id/activity_bg"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
/>

<!-- Toolbar-->
<RelativeLayout
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="50dp">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/navigation_back_white"
android:layout_centerVertical="true"
android:layout_marginLeft="15dp"
/>
<TextView
android:id="@+id/title_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textSize="18sp"
android:textColor="@android:color/white"
/>
</RelativeLayout>

<android.support.v4.view.ViewPager
android:id="@+id/my_viewpager"
android:layout_width="wrap_content"
android:layout_height="300dp"
android:clipChildren="false"
android:layout_marginLeft="50dp"
android:layout_marginRight="50dp"
android:layout_centerInParent="true"
/>
<com.zhouwei.indicatorview.CircleIndicatorView
android:id="@+id/indicatorView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="60dp"
android:layout_centerHorizontal="true"
app:indicatorSelectColor="#C79EFE"
app:indicatorSpace="5dp"
app:indicatorRadius="8dp"
app:enableIndicatorSwitch="false"
app:indicatorTextColor="@android:color/white"
app:fill_mode="number"
app:indicatorColor="#C79EFE"
/>
<TextView
android:id="@+id/skin_desc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_below="@+id/my_viewpager"
android:layout_marginTop="20dp"
android:textColor="@android:color/white"
android:textSize="18sp"
/>
</RelativeLayout>

2, Activity代码:
package demo.spdbank.hcq.com.viewpager_lol;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.widget.ImageView;
import android.widget.TextView;


import com.zhouwei.blurlibrary.EasyBlur;
import com.zhouwei.indicatorview.CircleIndicatorView;

/**
* Created by zhouwei on 17/5/21.
*/

public class MainActivity extends AppCompatActivity {
private ViewPager mViewPager;
private VPAdapter mVPAdapter;
private ImageView mImageBg;
private CircleIndicatorView mCircleIndicatorView;
private TextView mTitle,mDesc;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);
View view = findViewById(R.id.toolbar);
StatusBarUtils.setTranslucentImageHeader(this, 0,view);
initView();
}

private void initView() {
mViewPager = (ViewPager) findViewById(R.id.my_viewpager);
mImageBg = (ImageView) findViewById(R.id.activity_bg);
mCircleIndicatorView = (CircleIndicatorView) findViewById(R.id.indicatorView);
mTitle = (TextView) findViewById(R.id.title_name);
mDesc = (TextView) findViewById(R.id.skin_desc);

mTitle.setText("黑暗之女");
mViewPager.setPageTransformer(false,new CustomViewPagerTransformer(this));
// 添加监听器
mViewPager.addOnPageChangeListener(onPageChangeListener);
mVPAdapter = new VPAdapter(getSupportFragmentManager());
mViewPager.setAdapter(mVPAdapter);
mViewPager.setOffscreenPageLimit(3);
// Indicator 和ViewPager 建立关联
mCircleIndicatorView.setUpWithViewPager(mViewPager);
// 首次进入展示第二页
mViewPager.setCurrentItem(1);


}

@Override
public boolean onTouchEvent(MotionEvent event) {
return mViewPager.onTouchEvent(event);
}

private ViewPager.OnPageChangeListener onPageChangeListener = new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

}

@Override
public void onPageSelected(int position) {
Bitmap source = BitmapFactory.decodeResource(getResources(),VPAdapter.RES[position]);
Bitmap bitmap = EasyBlur.with(getApplicationContext())
.bitmap(source)
.radius(20)
.blur();
mImageBg.setImageBitmap(bitmap);

mDesc.setText(mVPAdapter.getPageTitle(position));
}

@Override
public void onPageScrollStateChanged(int state) {

}
};
}


ViewPager的每一个页面用Fragment 来展示的,Fragment代码如下:


package demo.spdbank.hcq.com.viewpager_lol;

import android.animation.ObjectAnimator;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
* Created by zhouwei on 17/5/25.
*/

public class ItemFragment extends Fragment {
private PolygonView mPolygonView;
public static ItemFragment newInstance(int resId){
ItemFragment itemFragment = new ItemFragment();
Bundle bundle = new Bundle();
bundle.putInt("resId",resId);
itemFragment.setArguments(bundle);
return itemFragment;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.view_pager_muti_layout,null);
mPolygonView = (PolygonView) view.findViewById(R.id.item_image);
// 做一个属性动画
ObjectAnimator animator = ObjectAnimator.ofFloat(mPolygonView,"rotation",0f,10f);
animator.setDuration(10);
animator.start();
return view;
}

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
int resId = getArguments().getInt("resId");
mPolygonView.setImageResource(resId);// 设置图片
}
}

   Adapter:
package demo.spdbank.hcq.com.viewpager_lol;

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;

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

/**
* Created by zh
ouwei on 17/5/21.
*/

public class VPAdapter extends FragmentPagerAdapter {
public static final int []RES = new int[]{R.drawable.skin2,R.drawable.skin3,R.drawable.skin4
,R.drawable.skin5,R.drawable.skin6,R.drawable.skin7,R.drawable.skin8,R.drawable.skin9,R.drawable.skin10,R.drawable.skin11};

public static final String TITLE[] = new String[]{"哥特萝莉","小红帽","安妮梦游仙境","舞会公主","冰爽烈焰","安博斯与提妮",
"科学怪熊的新娘","你见过我的熊猫吗?安妮","甜心宝贝","海克斯科技"};
private List<Fragment> mFragments = new ArrayList<>();

public VPAdapter(FragmentManager fm){
super(fm);
for(int i=0;i<RES.length;i++){
mFragments.add(ItemFragment.newInstance(RES[i]));
}
}
@Override
public int getCount() {
return mFragments.size();
}

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

@Override
public Fragment getItem(int position) {
return mFragments.get(position);
}

@Override
public CharSequence getPageTitle(int position) {
return TITLE[position];
}

/* @Override
public Object instantiateItem(ViewGroup container, int position) {
*//*View view = LayoutInflater.from(container.getContext()).inflate(R.layout.view_pager_muti_layout,null);
PolygonView imageView = (PolygonView) view.findViewById(R.id.item_image);
imageView.setImageResource(RES[position]);
container.addView(view);
return view;*//*
return mFragments.get(position);
}*/


}









智能推荐

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
© 2014-2019 ITdaan.com 粤ICP备14056181号  

赞助商广告