乘着中午休息时间,随便写点

这里是一个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
* 如果在其layout中添加的子view不是规则的,那么还是按照width来跑一页
* 这里的width值是构造函数设置的。通过{@link #setPageWidth(int)}来设置宽度
* 在手动滑动的时候,动画会停止,开启手动滑动{@link #enableSlide(boolean)}
* 如果手动滑到了2个页面之间,那么在调用 {@link #previous()} 或 {@link #next()} 会移动一个scrollX 求 width的摸值
* 注意!!!不需要再设置linearLayou,已经默认设置好,通过{@link #addPageView(View)} 来添加page
* 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 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();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 getPageViews() {return nPageViewsReference;}@Overrideprotected 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);}}/** * 下一页, 如果动画没有结束,调用没有效果
* 如果不完整会显示完整 */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();}}}/** * 上一页, 如果动画没有结束,调用没有效果
* 如果不完整会显示完整 */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();}}}@Overridepublic void onAnimationStart(Animator animation) {nIsEndAnimation = false;setEnabled(false);}@Overridepublic void onAnimationEnd(Animator animation) {nIsEndAnimation = true;nInPageView.in();setEnabled(true);}@Overridepublic void onAnimationCancel(Animator animation) {nIsEndAnimation = true;setEnabled(true);}@Overridepublic void onAnimationRepeat(Animator animation) {}@Overridepublic 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基类
* 它尽可能的对这些页面进行了抽象,但依旧不是很理想
* 对整个界面有一个rootView,是一个{@link RelativeLayout}对象
* 另外还有2个{@link RelativeLayout}对象 分别是上容器和下容器
* 在上容器里面定义了2个按钮,一个是“上一步” 另一个是“跳过”
* {@link #in()} , {@link #out()} 表示page完成进入和开始退出回调
* @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() {@Overridepublic void onClick(View v) {nPageControlView.previous();}});nSkipView.setOnClickListener(new OnClickListener() {@Overridepublic 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动画开源库

布局文件

                                    





更多相关文章

  1. Android(安卓)ProgressDialog的使用
  2. Android(安卓)uses-permission大全
  3. AndroidManifest.xml - activity 详细说明
  4. LinearLayout布局中layout_weight的用法
  5. android给listview设置分割线Divider样式
  6. Android设置上下边框或者左右边框
  7. Android(安卓)Studio中点击按钮跳转到其他页面
  8. Android实现自定义的 时间日期 控件
  9. Android(安卓)关于WebView的相关属性

随机推荐

  1. Android(安卓)ProgressDialog工具类
  2. Android(安卓)基础知识
  3. 线性布局 LinearLayout
  4. CTS 和 GMS
  5. Android的语言设置(一)
  6. Android(安卓)组件之Service解析
  7. AIDL 进程间通信
  8. Android(安卓)蓝牙耳机录音以及蓝牙耳机
  9. android获取空间的宽度高度 的方法
  10. Android(安卓)触摸事件机制(四) ViewGrou