VerticalLinearLayout自定义ViewGroup界面

最近在一个大神的博客里看到了有关自定义ViewGroup界面的文章,感觉很有用学习了一下,给大家分享一下

这位大神的博客:http://blog.csdn.net/lmj623565791/article/details/23692439

转载请注明:http://blog.csdn.net/lovemy_baby/article/details/51260022

下面我们看看代码的效果图:



废话不多说,我们进入正题,首先我们看看main.xml:

<com.itheima.vertivallinearlayoutone.VerticalLinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/id_main_ly"
    android:layout_width="match_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    android:background="#fff" >


    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="@drawable/w02" >


        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="hello" />
    </RelativeLayout>


    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="@drawable/w03" >


        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:background="#fff"
            android:text="hello" />
    </RelativeLayout>


    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="@drawable/w04" >


        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="hello" />
    </RelativeLayout>


    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="@drawable/w05" >


        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="hello" />
    </RelativeLayout>


</com.itheima.vertivallinearlayoutone.VerticalLinearLayout>

这里没有什么说的,接下来我们看看主要的代码,就是VerticalLinearLayout.java代码:

package com.itheima.vertivallinearlayoutone;


import android.content.Context;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Scroller;


public class VerticalLinearLayout extends ViewGroup {

/**
* 屏幕的高度
*/
private int mScreenHeight;
/**
* 手指按下时的getScrollY
*/
private int mScrollStart;
/**
* 手指抬起时的getScrollY
*/
private int mScrollEnd;
/**
* 记录移动时的Y
*/
private int mLastY;
/**
* 滚动的辅助类
*/
private Scroller mScroller;
/**
* 是否正在滚动
*/
private boolean isScrolling;
/**
* 加速度检测
*/
private VelocityTracker mVelocityTracker;
/**
* 记录当前页
*/
private int currentPage = 0;

private OnPageChangeListener mOnPageChangeListener;


public VerticalLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
//获取屏幕的高度
WindowManager wm=(WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics=new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
mScreenHeight=outMetrics.heightPixels;

mScroller=new Scroller(context);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);

int count=getChildCount();
for(int i=0;i<count;++i){
View childView=getChildAt(i);
measureChild(childView, widthMeasureSpec, heightMeasureSpec);
}
}


@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (changed) {
int childCount=getChildCount();
MarginLayoutParams lp=(MarginLayoutParams)getLayoutParams();
lp.height=mScreenHeight*childCount;
setLayoutParams(lp);
for(int i=0;i<childCount;i++){
View child=getChildAt(i);
if (child.getVisibility()!=View.GONE) {
child.layout(l, i*mScreenHeight, r, (i+1)*mScreenHeight);
}
}
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {

if (isScrolling) {
return super.onTouchEvent(event);
}
int action=event.getAction();
int y=(int)event.getY();
obtainVelocity(event);
switch (action) {
case MotionEvent.ACTION_DOWN:
mScrollStart=getScrollY();
mLastY=y;
break;
case MotionEvent.ACTION_MOVE:
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
int dy=mLastY-y;
int scrollY=getScrollY();
if (y<0&&scrollY+dy<0) {
dy=-scrollY;
}
if (y>0&&scrollY+dy>getHeight()-mScreenHeight) {
dy=getHeight()-mScreenHeight-scrollY;
}
scrollBy(0, dy);
mLastY=y;
break;
case MotionEvent.ACTION_UP:
mScrollEnd=getScrollY();
int dScrollY=mScrollEnd-mScrollStart;
if (wantScrollToNext()) {
if (shouldScrollToNext()) {
mScroller.startScroll(0, getScrollY(), 0, mScreenHeight-dScrollY);
}else {
mScroller.startScroll(0, getScrollY(), 0, -dScrollY);
}
}
if (wantScrollToPre()) {
if (shouldScrollToPre()) {
mScroller.startScroll(0, getScrollY(), 0, -mScreenHeight-dScrollY);
}else {
mScroller.startScroll(0, getScrollY(), 0, -dScrollY);
}
}
isScrolling=true;
postInvalidate();
recycleVelocity();
break;
}
return true;

}
private boolean shouldScrollToNext(){
return mScrollEnd-mScrollStart>mScreenHeight/2||Math.abs(getVelocity())>600;
}
private boolean wantScrollToNext(){
return mScrollEnd>mScrollStart;
}
private boolean shouldScrollToPre(){
return mScrollStart-mScrollEnd>mScreenHeight/2||Math.abs(getVelocity())>600;
}
private boolean wantScrollToPre(){
return mScrollStart>mScrollEnd;
}
@Override
public void computeScroll()
{
super.computeScroll();
if (mScroller.computeScrollOffset())
{
scrollTo(0, mScroller.getCurrY());
postInvalidate();
} else
{


int position = getScrollY() / mScreenHeight;


Log.e("xxx", position + "," + currentPage);
if (position != currentPage)
{
if (mOnPageChangeListener != null)
{
currentPage = position;
mOnPageChangeListener.onPageChange(currentPage);
}
}


isScrolling = false;
}


}
//获取y方向的加速度
private int getVelocity(){
mVelocityTracker.computeCurrentVelocity(1000);
return (int)mVelocityTracker.getYVelocity();
}
//释放资源
private void recycleVelocity(){
if (mVelocityTracker!=null) {
mVelocityTracker.recycle();
mVelocityTracker=null;
}
}
private void obtainVelocity(MotionEvent event){
if (mVelocityTracker==null) {
mVelocityTracker=VelocityTracker.obtain();
}
mVelocityTracker.addMovement(event);
}
//色织回调接口
public void setOnPageChangeListener(OnPageChangeListener onPageChangeListener){
mOnPageChangeListener=onPageChangeListener;
}
public interface OnPageChangeListener{
void onPageChange(int currentPage);
}


}

有一些已经有注释解释了,我们就不做多余赘诉,我们就解释一些其他的:

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);

int count=getChildCount();
for(int i=0;i<count;++i){
View childView=getChildAt(i);
measureChild(childView, widthMeasureSpec, heightMeasureSpec);
}
}

对于measure官方的API是这样说的:

Measure the view and its content to determine the measured width and the measured height. This method is invoked by measure(int, int) and should be overriden by subclasses to provide accurate and efficient measurement of their contents.

意思就是测量他的高度和宽度,根据两个参数提供准确的测量内容。

public boolean onTouchEvent(MotionEvent event) {

if (isScrolling) {
return super.onTouchEvent(event);
}
int action=event.getAction();
int y=(int)event.getY();
obtainVelocity(event);
switch (action) {
case MotionEvent.ACTION_DOWN:
mScrollStart=getScrollY();
mLastY=y;
break;
case MotionEvent.ACTION_MOVE:
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
int dy=mLastY-y;
int scrollY=getScrollY();
if (y<0&&scrollY+dy<0) {
dy=-scrollY;
}
if (y>0&&scrollY+dy>getHeight()-mScreenHeight) {
dy=getHeight()-mScreenHeight-scrollY;
}
scrollBy(0, dy);
mLastY=y;
break;
case MotionEvent.ACTION_UP:
mScrollEnd=getScrollY();
int dScrollY=mScrollEnd-mScrollStart;
if (wantScrollToNext()) {
if (shouldScrollToNext()) {
mScroller.startScroll(0, getScrollY(), 0, mScreenHeight-dScrollY);
}else {
mScroller.startScroll(0, getScrollY(), 0, -dScrollY);
}
}
if (wantScrollToPre()) {
if (shouldScrollToPre()) {
mScroller.startScroll(0, getScrollY(), 0, -mScreenHeight-dScrollY);
}else {
mScroller.startScroll(0, getScrollY(), 0, -dScrollY);
}
}
isScrolling=true;
postInvalidate();
recycleVelocity();
break;
}
return true;

}

安卓代码有很强的块状结构,所以了解以后就显得得心应手,上面的代码意思就是先记录点击事件和点击的初始位置,当点击的时候,用y记录位置,移动的时候记录移动的距离,当按键抬起的时候得到距离,如果距离大于触发事件的最小距离的时候,事件被触发,基本就是如此。

下面是mainActivity.java代码:

package com.itheima.vertivallinearlayoutone;


import com.itheima.vertivallinearlayoutone.VerticalLinearLayout.OnPageChangeListener;


import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;


public class MainActivity extends Activity {
private VerticalLinearLayout mLayout;


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLayout=(VerticalLinearLayout)findViewById(R.id.id_main_ly);
mLayout.setOnPageChangeListener(new OnPageChangeListener() {

@Override
public void onPageChange(int currentPage) {
Toast.makeText(MainActivity.this, "第"+(currentPage+1)+"页", 0).show();
}
});
}
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值