Android 记录1 自定义View

来源:互联网 发布:如何查看域名劫持 编辑:程序博客网 时间:2024/06/10 06:13

                                                                                                   Android 记录1  自定义View(ScrollLayout)

        慢慢开始学习android基础,菜鸟第一步.
       
开篇之前,需要感谢 http://blog.csdn.net/wwj_748/article/details/10110373  ,参考博主的文章来学习.

 

          该自定义view的作用:手动滑动切换界面,有点类似于刚安装apk之后 新特性界面浏览。

 

          1. layout布局如下:

            
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context=".MainActivity" >    <com.wty.demo.myscroller.MyScrollLayout          android:id="@+id/ScrollLayout"          android:layout_width="match_parent"          android:layout_height="match_parent" >            <FrameLayout              android:layout_width="match_parent"              android:layout_height="match_parent"              android:background="@drawable/guide_1" >          </FrameLayout>            <FrameLayout              android:layout_width="match_parent"              android:layout_height="match_parent"              android:background="@drawable/guide_2" >          </FrameLayout>        <FrameLayout              android:layout_width="match_parent"              android:layout_height="match_parent"              android:background="@drawable/guide_3" >          </FrameLayout>            <FrameLayout              android:layout_width="match_parent"              android:layout_height="match_parent"              android:background="@drawable/guide_4" >          </FrameLayout>            <FrameLayout              android:layout_width="match_parent"              android:layout_height="match_parent"              android:background="#00000000" >          </FrameLayout>    </com.wty.demo.myscroller.MyScrollLayout> </RelativeLayout>


               布局介绍:自定义一个MyScrollLayout组件,该组件包含5个FrameLayout.

       2.自定义view代码实现:

package com.wty.demo.myscroller;import android.content.Context;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.view.VelocityTracker;import android.view.View;import android.view.ViewGroup;import android.widget.Scroller;/* * ViewGroup 继承于View, * 因此也可以使用View ScrollTo/ScrollBy 方法(自定义的滑动控件中,一般会使用这个两个方法) * 当ScrollX=负数,坐标向右边移动,当ScrollY=负数时,坐标向上边移动 * 原因:tmpr.set(l - scrollX, t - scrollY, r - scrollX, b - scrollY)设置一个view需要绘制的矩形 * 负负得正,负正得负,再结合android直角坐标系的概念右正左负 * getScrollX/getScrollY  *  *  * */public class MyScrollLayout extends ViewGroup {private String TAG="WTY";private VelocityTracker mVelocityTracker;       // 用于判断甩动手势   private static final int SNAP_VELOCITY = 600;   // 滑动距离   private Scroller mScroller;                     // 滑动控制器   private int mCurScreen;                         // 当前屏幕   private int mDefaultScreen = 0;                 // 默认屏幕   private float mLastMotionX;public MyScrollLayout(Context context){super(context);init(context);}public MyScrollLayout(Context context, AttributeSet attrs, int defStyle) {  super(context, attrs, defStyle);  init(context);  }  public MyScrollLayout(Context context, AttributeSet attrs) {  super(context, attrs);  init(context);  }private void init(Context context) {// TODO Auto-generated method stubmCurScreen = mDefaultScreen;mScroller = new Scroller(context);}@Override  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  super.onMeasure(widthMeasureSpec, heightMeasureSpec);  final int width = MeasureSpec.getSize(widthMeasureSpec);  final int childCount = getChildCount();//获得子元素的总个数 ,这里是5 for (int i = 0; i < childCount; i++) {/*调用每一个子元素的measure方法来测量宽以及高度*/getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);  }  scrollTo(mCurScreen * width, 0);        // 设置滚动视图的位置,默认是滚动到(0,0)   }@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {// TODO Auto-generated method stubif(changed){//有改变才重新布局/* * 这里最终整体效果:1 2 3 4 5 (每一个都占满屏幕,宽度也跟屏幕一样) *  * */int childLeft =0;final int childCount = getChildCount();for(int i=0;i<childCount;i++){final View childView = getChildAt(i);//得到孩子if(childView.getVisibility()!=View.GONE){//如果childview需要占用空间,也就 Visable or inVisable,需要为它布局final int childWidth = childView.getMeasuredWidth();//获得view测量的宽度childView.layout(childLeft, 0,childLeft+childWidth , childView.getMeasuredHeight());childLeft+=childWidth;}}}}@Overridepublic boolean onTouchEvent(MotionEvent event){final int action = event.getAction();/*getX/getY 一直为正,android直角坐标系*/final float x = event.getX();switch(action){case MotionEvent.ACTION_DOWN://手指按下if(mVelocityTracker ==null){mVelocityTracker = VelocityTracker.obtain();//得到一个实例mVelocityTracker.addMovement(event);}if(!mScroller.isFinished()){mScroller.abortAnimation();}mLastMotionX=x;break;case MotionEvent.ACTION_MOVE://手指移动int deltaX =(int)(mLastMotionX-x);//当从左向右滑动,x>mLastMotionX,deltaX为负数                                  //当从右向左滑动,x<mLastMotionX,deltaX为正数if(IsCanMove(deltaX)){if(mVelocityTracker !=null){mVelocityTracker.addMovement(event);}mLastMotionX =x;scrollBy(deltaX,0);//在原来基础上再移动(deltaX,0)}break;case MotionEvent.ACTION_UP://手指放开int velocityX=0;if(mVelocityTracker !=null){mVelocityTracker.addMovement(event);//设置单位,1000 表示每秒多少像素(pix/second),1代表每微秒多少像素(pix/millisecond)。mVelocityTracker.computeCurrentVelocity(1000);velocityX=(int)mVelocityTracker.getXVelocity();//获得水平方向的速率}if(velocityX > SNAP_VELOCITY && mCurScreen>0){//从左向右划返回正数,还没有到第一个界面snapToScreen(mCurScreen - 1);//滑到左边界面}else if(velocityX<-SNAP_VELOCITY && mCurScreen < getChildCount()-1){//从右向左划返回负数,还没有到最后一个界面snapToScreen(mCurScreen+1);//滑到右边界面}else{//当滑动速度很慢的时候snapToDestination();}if(mVelocityTracker !=null){mVelocityTracker.recycle();mVelocityTracker=null;}break;}return true;}@Override  public void computeScroll() {      Log.d(TAG,"computeScroll");if (mScroller.computeScrollOffset()) { //判断滑动动画是否已结束 ,为true表示还没有结束 ////如果mScroller没有调用startScroll,这里将会返回falsescrollTo(mScroller.getCurrX(), mScroller.getCurrY()); /* * postInvalidate执行后,会去调computeScroll 方法,而这个方法里再去调postInvalidate, * 这样就可以不断地去调用scrollTo方法了,直到mScroller动画结束,当然第一次时, * 我们需要手动去调用一次postInvalidate才会去调用 * */postInvalidate();  //重绘}  }//滑动到目标位置,当缓慢拉到的时候,需要判断当前的ScrollX偏移量到底偏向于哪一个界面()也就是当前能看到的两个界面到底哪个占的比例大public void snapToDestination(){final int screenWidth=getWidth();final int destScreen=(getScrollX()+screenWidth/2)/screenWidth;snapToScreen(destScreen);}public void snapToScreen(int whichScreen){   //获得有效的页面   whichScreen = Math.max(0, Math.min(whichScreen, getChildCount()-1));//界面不能小于0又不能大于最后一个       if(getScrollX() !=(whichScreen*getWidth())){//偏移量没有正好等于屏幕宽度的whichScreen倍,一般来说都不相等              final int delta = whichScreen*getWidth()-getScrollX();       mScroller.startScroll(getScrollX(), 0, delta, 0, Math.abs(delta));       //开始滚动,设置初始位置--》结束位置 & 持续时间              mCurScreen=whichScreen;       invalidate();//重绘布局       }}/* * 判断是否可以移动 * */private boolean IsCanMove(int deltaX){if(getScrollX()<=0 && deltaX <0){ //从左向右,不能再继续滑动return false;}if(getScrollX()>=(getChildCount()-1)*getWidth()&&deltaX>0){//从右向左,不能再继续滑动return false;}return true;}}


      3.mainActivity的实现,就是简单的加载布局文件:
      

package com.wty.demo.myscroller;import android.os.Bundle;import android.app.Activity;import android.view.Menu;public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}}


      刚开始,希望把自己所了解的以及所理解的知识,慢慢积累起来记录起来.

    

 

0 0
原创粉丝点击