您的位置:首页 > 移动开发 > Android开发

android 页面容器 下一页很上一页view

2016-01-06 13:58 666 查看
乘着中午休息时间,随便写点

这里是一个page容器可以包含多个BasePageView

容器代码:

package com.pingyijinren.guider.setting.view;

import java.util.ArrayList;
import java.util.Collection;

import com.nineoldandroids.animation.Animator;
import com.nineoldandroids.animation.Animator.AnimatorListener;
import com.nineoldandroids.animation.ValueAnimator;
import com.nineoldandroids.animation.ValueAnimator.AnimatorUpdateListener;
import com.pingyijinren.guider.Constants;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.LinearLayout;

/**既可以滑动,又可以翻页的scrollview<br>
* 如果在其layout中添加的子view不是规则的,那么还是按照width来跑一页<br>
* 这里的width值是构造函数设置的。通过{@link #setPageWidth(int)}来设置宽度<br>
* 在手动滑动的时候,动画会停止,开启手动滑动{@link #enableSlide(boolean)}<br>
* 如果手动滑到了2个页面之间,那么在调用 {@link #previous()} 或 {@link #next()} 会移动一个scrollX 求 width的摸值 <br>
* 注意!!!不需要再设置linearLayou,已经默认设置好,通过{@link #addPageView(View)} 来添加page<br>
* TODO 添加不规则的view可以很好的展现
* @author WenYF
*
*/
public class PageLayout extends LinearLayout implements AnimatorListener
, AnimatorUpdateListener{
private static final String TAG =  "AnimationHorizontalScrollView";

@SuppressWarnings("unused")
private Context nContext;
/**
* 动画值发生器
*/
private ValueAnimator nPositiveValueAnimator;
/**
* 页面的宽度
*/
private int nPageWidth;
/**
* 是否设置了页面宽度
*/
private boolean nHasSetWidth;
/**
* 页面数量
*/
private int nPageCounts;
/**
* 是否设置了页面数量
*/
private boolean nHasSetPageCounts;
/**
* 当前页面动画的开始位置
*/
private int nCurrentStartX;

/**
* 动画是否打开
*/
private boolean nIsEnableAnimation;
/**
* 动画是否结束
*/
private boolean nIsEndAnimation;

private Collection<BasePageView> nPageViewsReference;
/**
* 进入的page
*/
private BasePageView nInPageView;
/**
* 出去的page
*/
private BasePageView nOutPageView;

private OnPageListener nPageListener;

public void setPageListener(OnPageListener listener) {
nPageListener = listener;
}

/**只能通过改函数来动态设置本view,counts和width一旦设置不能修改
* @param context 上下文
* @param pageCounts 子view的数量 如果为-1则交给scroll view自己来监视有多少个view
* @param pageWidth 一页的宽度,-1表示由scroll view来测量自己的宽度
*/
public PageLayout(Context context, int pageCounts, int pageWidth) {
super(context);
nContext = context;
initView(pageCounts, pageWidth);
}

/**使用默认值构造,{@link #PageHorizontalScrollView(Context, int, int)}
* @param context
*/
public PageLayout(Context context) {
this(context, null);
}

/**使用默认值构造,{@link #PageHorizontalScrollView(Context, int, int)}
* @param context
*/
public PageLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

/**使用默认值构造,{@link #PageHorizontalScrollView(Context, int, int)}
* @param context
*/
public PageLayout(Context context, AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
nContext = context;
initView(-1, -1);

}

private void initView(int counts, int width) {
nPageViewsReference = new ArrayList<BasePageView>();

ValueAnimator.setFrameDelay(30);
nPositiveValueAnimator = ValueAnimator.ofInt(0, width);
nPositiveValueAnimator.setDuration(Constants.ANIMATION_SPEED);
nPositiveValueAnimator.addListener(this);
nPositiveValueAnimator.addUpdateListener(this);

nPageWidth = width;
nHasSetWidth = width != -1;

nPageCounts = counts;
nHasSetPageCounts = nPageCounts != -1;

nIsEndAnimation = true;
nIsEnableAnimation = true;
Log.d(TAG, "width = " + width + ", counts = " + nPageCounts);

setHorizontalScrollBarEnabled(false);
setHorizontalFadingEdgeEnabled(false);

}

/**
* @param counts 子view的数量 如果为-1则交给scroll view自己来监视有多少个view
*/
public void setPageCounts(int counts) {
if (counts == -1) {
nHasSetPageCounts = false;
} else {
nHasSetPageCounts = true;
nPageCounts = counts;
}
}

/**
* @param width 一页的宽度,-1表示由scroll view来测量自己的宽度
*/
public void setPageWidth(int width) {
if (width == -1) {
nHasSetWidth = false;
} else {
nHasSetWidth = true;
nPageWidth = width;
}
}

/**打开或关闭跳转页面动画
* @param enable
*/
public void enableAnimation(boolean enable) {
nIsEnableAnimation = enable;
}

/** 给容器添加view,而不是scroll view
* @param page
*/
public void addPageView(BasePageView page) {
addView(page);
nPageViewsReference.add(page);
}

/** 给容器添加view,而不是scroll view
* @param child
* @param index
*/
public void addPageView(BasePageView page, int index) {
addView(page, index);
nPageViewsReference.add(page);
}

/** 给容器添加view,而不是scroll view
* @param child
* @param index
* @param params
*/
public void addPageView(BasePageView page, int index,
android.view.ViewGroup.LayoutParams params) {
addView(page, params);
nPageViewsReference.add(page);
}

/**  给容器添加view,而不是scroll view
* @param child
* @param width
* @param height
*/
public void addPageView(BasePageView page, int width, int height) {
addView(page, width, height);
nPageViewsReference.add(page);
}

/** 给容器添加view,而不是scroll view
* @param child
* @param params
*/
public void addPageView(BasePageView page, android.view.ViewGroup.LayoutParams params) {
addView(page, params);
nPageViewsReference.add(page);
}

public  Collection<BasePageView> getPageViews() {
return nPageViewsReference;
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
Log.d(TAG, "onMeasure view width = " + getWidth());

if (!nHasSetWidth) {
nPositiveValueAnimator.setIntValues(0, getWidth());
nPageWidth = getWidth();
}

if (!nHasSetPageCounts) {
nPageCounts = getChildCount();
Log.d(TAG, "onMeasure page Counts = " + nPageCounts);
}

}

/**
* 下一页, 如果动画没有结束,调用没有效果<br>
* 如果不完整会显示完整
*/
public void next() {
Log.d(TAG, "next scrollx = " + getScrollX());

if (nPageCounts <= 0 || nPageWidth <= 0) {
Log.w(TAG, "the values is invalid, page counts = " + ", width = " + nPageWidth);
return;
}

// 最后一页,通知
if (getScrollX() >= nPageWidth * (nPageCounts - 1) && nPageListener != null) {
nPageListener.onEnd();
}

if (getScrollX() < nPageWidth * (nPageCounts - 1) && nIsEndAnimation) {
int inPageIndex = getScrollX() / nPageWidth + 1;
int outPageIndex = getScrollX() / nPageWidth;

Log.d(TAG, "inPageIndex = " + inPageIndex);
Log.d(TAG, "outPageIndex = " + outPageIndex);

nInPageView = (BasePageView)
getChildAt(inPageIndex);
nOutPageView = (BasePageView)
getChildAt(outPageIndex);

// 得到要移动的距离
int deltaX = nPageWidth - (getScrollX() % nPageWidth) != 0 ?
nPageWidth - (getScrollX() % nPageWidth) : nPageWidth;
Log.d(TAG, "next deltaX = " + deltaX);

// 前一页离开
nOutPageView.out();

if (!nIsEnableAnimation) {
nCurrentStartX = getScrollX() + deltaX;
scrollTo(nCurrentStartX, 0);
// 后一页进入
nInPageView.in();
} else {
nCurrentStartX = getScrollX();
nPositiveValueAnimator.setIntValues(0, deltaX);
nPositiveValueAnimator.start();
}

}
}
/**
* 上一页, 如果动画没有结束,调用没有效果<br>
* 如果不完整会显示完整
*/
public void previous() {
Log.d(TAG, "previous scrollx = " + getScrollX());

if (nPageCounts <= 0 || nPageWidth <= 0) {
Log.w(TAG, "the values is invalid, page counts = " + nPageCounts + ", width = " + nPageWidth);
return;
}

if (getScrollX() > 0  && nIsEndAnimation) {
int totleWidth = nPageCounts * nPageWidth;
int inPageIndex = nPageCounts - 1 - ((totleWidth - (getScrollX() + nPageWidth)) / nPageWidth + 1);
int outPageIndex = nPageCounts - 1 - (totleWidth - (getScrollX() + nPageWidth)) / nPageWidth;

Log.d(TAG, "inPageIndex = " + inPageIndex);
Log.d(TAG, "outPageIndex = " + outPageIndex);

nInPageView = (BasePageView)
getChildAt(inPageIndex);
nOutPageView = (BasePageView)
getChildAt(outPageIndex);

// 得到要移动的距离
int deltaX = getScrollX() % nPageWidth != 0 ? getScrollX() % nPageWidth : nPageWidth;
Log.d(TAG, "previous deltaX = " + deltaX);

// 前一页离开
nOutPageView.out();

nCurrentStartX = getScrollX() - deltaX;
if (!nIsEnableAnimation) {
scrollTo(nCurrentStartX, 0);
// 后一页进入
nInPageView.in();
} else {
nPositiveValueAnimator.setIntValues(0, deltaX);
nPositiveValueAnimator.reverse();
}

}
}

@Override
public void onAnimationStart(Animator animation) {
nIsEndAnimation = false;
setEnabled(false);
}

@Override
public void onAnimationEnd(Animator animation) {
nIsEndAnimation = true;

nInPageView.in();

setEnabled(true);
}

@Override
public void onAnimationCancel(Animator animation) {
nIsEndAnimation = true;
setEnabled(true);
}

@Override
public void onAnimationRepeat(Animator animation) {

}

@Override
public void onAnimationUpdate(ValueAnimator animation) {
int values = nCurrentStartX + (Integer) animation.getAnimatedValue();
Log.v(TAG, "values = " + values);
scrollTo((int)values, 0);
}

public interface OnPageListener {
public void onEnd();
}
}


这里是BasePageView
有一点针对业务定制,去掉即可,结构不变:

package com.pingyijinren.guider.setting.view;

import com.pingyijinren.guider.R;

import android.app.Dialog;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;

/**这是一个开机引导中页面的view基类<br>
* 它尽可能的对这些页面进行了抽象,但依旧不是很理想<br>
* 对整个界面有一个rootView,是一个{@link RelativeLayout}对象<br>
* 另外还有2个{@link RelativeLayout}对象 分别是上容器和下容器<br>
* 在上容器里面定义了2个按钮,一个是“上一步” 另一个是“跳过”<br>
* {@link #in()} , {@link #out()} 表示page完成进入和开始退出回调<br>
* @author WenYF
*
*/
public abstract class BasePageView extends RelativeLayout{

/**
* page中唯一的一个对话框
*/
protected Dialog nDialog;
/**
* 页面的根view
*/
protected RelativeLayout nRootView;
/**
* 上容器
*/
protected RelativeLayout nTopViewContainer;
/**
* 下容器
*/
protected RelativeLayout nBottomViewContainer;

/**
* 上一步按钮,父view是{@link #nTopViewContainer}
*/
protected ImageView nPreviousView;
/**
* 跳过按钮,父view是{@link #nTopViewContainer}
*/
protected ImageView nSkipView;
/**
* 保护此页面的容器view
*/
protected PageLayout nPageControlView;
/**
* top container 用来显示title的panel
*/
protected ImageWithTextView nTopTitlePanal;

public BasePageView(Context context) {
this(context, null);
}
public BasePageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public BasePageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);

LayoutInflater.from(context).inflate(R.layout.container_view_main, this, true);

nRootView = (RelativeLayout) findViewById(R.id.container_root);
nTopViewContainer = (RelativeLayout) findViewById(R.id.container_top);
nTopTitlePanal = (ImageWithTextView) findViewById(R.id.top_title_panal);

nBottomViewContainer = (RelativeLayout) findViewById(R.id.container_bottom);
nPreviousView = (ImageView) findViewById(R.id.button_previous);
nSkipView = (ImageView) findViewById(R.id.button_skip);

nPreviousView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
nPageControlView.previous();
}
});

nSkipView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
nPageControlView.next();
}
});
}

/**设置跳过和上一页按钮的visibility
* @param visibility
*/
public void setButtonViewVisibility(int visibility) {
nSkipView.setVisibility(visibility);
nPreviousView.setVisibility(visibility);
}

/**设置上下两个容器 Visibility 值
* @param visibility {@link View#VISIBLE} or {@link View#INVISIBLE} or {@link View#GONE}
*/
public void setContainerViewVisibility(int visibility) {
nTopViewContainer.setVisibility(visibility);
nBottomViewContainer.setVisibility(visibility);
}

/**设置底部的view容器的height
* @param height {@link RelativeLayout.LayoutParams} match_parent \ warp_content \ custom height
*/
public void setBottomContainerHeight(int height) {
RelativeLayout.LayoutParams params = (LayoutParams) nBottomViewContainer.getLayoutParams();
params.height = height;
nBottomViewContainer.setLayoutParams(params);
}

public void setPageControlView(PageLayout view) {
nPageControlView = view;
}

/**
* 页面完成进来的时候处理
*/
public abstract void in();
/**
* 页面开始出去的时候处理
*/
public abstract void out();
/**
* 释放view中可能没有办法释放的内存
*/
public abstract void destory();
}
注意,代码里面用到了http://download.csdn.net/detail/juy19901128/9392637的android动画开源库

布局文件

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.pingyijinren.guider.setting.activity.GuiderSettingActivity" >

<RelativeLayout
android:id="@+id/container_top"
android:layout_width="match_parent"
android:layout_height="125.33dp"
android:layout_marginTop="6.67dp"
android:layout_marginLeft="6.67dp"
android:layout_marginRight="6.67dp"
android:background="@drawable/top">

<ImageView
android:id="@+id/button_previous"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="9.33dp"
android:layout_marginTop="9.33dp"
android:clickable="true"
android:background="@android:color/transparent"
android:contentDescription="@string/text_image_view_desc"
android:src="@drawable/selector_button_previous"/>

<ImageView
android:id="@+id/button_skip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginRight="9.33dp"
android:layout_marginTop="9.33dp"
android:clickable="true"
android:background="@android:color/transparent"
android:contentDescription="@string/text_image_view_desc"
android:src="@drawable/selector_button_skip"/>

<com.pingyijinren.guider.setting.view.ImageWithTextView
android:id="@+id/top_title_panal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="35.33dp"
android:layout_centerHorizontal="true" >
</com.pingyijinren.guider.setting.view.ImageWithTextView>

</RelativeLayout>
<RelativeLayout
android:id="@+id/container_bottom"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/container_top"
android:layout_marginLeft="6.67dp"
android:layout_marginRight="6.67dp"
android:background="@drawable/bottom">

</RelativeLayout>

</RelativeLayout>


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: