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
- Android 记录1 自定义View
- android自定义View(1)
- Android 自定义View (1)
- Android 自定义View(1)
- android自定义view(1)
- 自定义View学习记录
- Android学习记录(九) android通过自定义view画进度。
- Android View---自定义View
- Android View---自定义View
- Android 自定义View学习(1)
- Android自定义View(1)
- Android自定义View训练【1】
- android 自定义view(1)
- android 自定义 View(1)
- Android自定义View(1)
- 自定义View相关知识记录
- 自定义view的一些记录
- 自定义View 细节点记录
- 2.3-6
- 【scikit-learn】如何进行模型参数的选择
- 面试题9:斐波拉契数列
- CT鸡的第一次
- 面试题10:求二进制中1的个数
- Android 记录1 自定义View
- 使用MySQL图形化工具Navicat创建表
- HDU 1481 树的性质(神坑)
- Java利用Zxing生成二维码
- Maven入门指南⑤:使用Nexus搭建Maven私服
- 2.3-7
- Android 常用 adb 命令总结
- JavaScript自学第4讲:JavaScript运算符介绍
- 建造者模式