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

这里是一个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动画开源库

布局文件

                                    


android 页面容器 下一页很上一页view_第1张图片


更多相关文章

  1. Android Studio中点击按钮跳转到其他页面
  2. [android]布局(容器)简介和使用方法
  3. android 输入键盘遮挡页面的问题
  4. 页面未随软键盘上升及android隐藏软键盘总结
  5. Android 页面惯性回弹效果,Nested接口接口简单实现。
  6. android获得屏幕高度和宽度
  7. android仿今日头条个人中心页面

随机推荐

  1. 美团DB数据同步到数据仓库的架构与实践
  2. MySQL 8忘记密码的最佳处理方式浅析
  3. MySQL主从延迟现象及原理分析详解
  4. mysql 8.0.13手动安装教程
  5. MySQL中无过滤条件的count详解
  6. MySQL中int最大值深入讲解
  7. Mysql主键和唯一键的区别点总结
  8. MySQL按时间统计数据的方法总结
  9. 实例讲解MySQL中乐观锁和悲观锁
  10. SQL和NoSQL之间的区别总结