Quantcast
Channel: CSDN博客移动开发推荐文章
Viewing all articles
Browse latest Browse all 5930

自定义控件03

$
0
0

#

scrollView

viewpager

fragment

handler 快速搜索

开源项目 slidingmenuhm

左滑 右滑 interceptTouchEvent拦截事件


☆☆☆☆☆去标题栏

// 在onCreate中 去掉标题栏 调用方法
// requestWindowFeature(Window.FEATURE_NO_TITLE);

去掉标题栏
全屏时需要同时加下面的两个item
<style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
        <item name="android:windowFullscreen">true</item>
        <item name="android:windowNoTitle">true</item>
        <!-- API 14 theme customizations can go here. -->
</style>


iv.setBackgroundResource(picture[i]);//填充背景窗口
iv.setImageResource(picture[i]);//显示的是图片实际的大小

☆☆☆☆☆ViewGroup

继承ViewGroup 需要重新测量,看布局宽和高的值
/*@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    //如果布局的宽和高是固定的值 设置measureChildren(0,0);否则 measureChildren(widthMeasureSpec, heightMeasureSpec);
    measureChildren(widthMeasureSpec, heightMeasureSpec);
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}*/

☆☆☆☆☆ViewGroup

自定义的类继承了RelativeLayout 不需要再次测量onmeasure();和排版onLayout();

ViewPager使用 实现图片无限循环播放

    public class MainActivity extends Activity {
    private int[] picture = new int[] { R.drawable.icon_1, R.drawable.icon_2,
            R.drawable.icon_3, R.drawable.icon_4, R.drawable.icon_5 };
    private String[] descs = { "为梦想坚持", "我相信我是黑马", "黑马公开课", "Google/IO",
            "轻松1w+" };
    private ArrayList<ImageView> list;// ImageView 图片
    private ArrayList<View> dots;// View 小黑点
    private ViewPager pager;
    private TextView tv_content;
    private LinearLayout ll_layout;
    private View currentView;
    /** 用handler实现自动滚动 **/
    private Handler handler = new Handler() {
        public void handleMessage(android.os.Message msg) {
            // 显示下一个图片
            pager.setCurrentItem(pager.getCurrentItem() + 1);
            // 再次发送,实现无限滚动
            handler.sendEmptyMessageDelayed(10, 3500);
        };
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 去掉标题栏
        // requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);
        /** 初始化数据 **/
        initData();
        /** 初始化adapter **/
        initAdapter();
        /** 设置pager滚动监听的事件 **/
        pager.setOnPageChangeListener(new Listen());

    }

    /** 屏幕可见时 实现自动滚动图片 **/
    @Override
    protected void onStart() {
        // 参数1:是标记 参数2:间隔时间
        handler.sendEmptyMessageDelayed(10, 3500);
        super.onStart();
    }

    /** 屏幕不可见时 关闭自动滚动图片 **/
    @Override
    protected void onStop() {
        // 10 用于识别handler,作为标记
        handler.removeMessages(10);
        super.onStop();
    }

    /** 设置pager滚动监听的事件 **/
    public class Listen implements OnPageChangeListener {
        // 滚动
        @Override
        public void onPageScrolled(int position, float positionOffset,
                int positionOffsetPixels) {

        }

        // 当一个新的页面被选中的时候调用
        @Override
        public void onPageSelected(int position) {
            // 小圆点和内容的改变 封装成方法,方便调用
            dot_contentChange(position);

        }

        // 当滑动页面的状态改变的时候调用
        @Override
        public void onPageScrollStateChanged(int state) {

        }

    }

    /** 小圆点和内容的改变 封装成方法,方便调用 **/
    private void dot_contentChange(int position) {
        // [1]动态改变小圆点的文本内容 数据在哪里存着就去哪里取
        tv_content.setText(descs[position % 5]);
        View dot = dots.get(position % 5);
        if (currentView != null) {
            currentView.setSelected(false);
        }
        // [2]更新小圆点的状态 小圆点在集合里面存着
        dot.setSelected(true);
        // [3]把dots.get(position % 5)赋值给currentView
        currentView = dot;
    }

    /** 初始化adapter **/
    private void initAdapter() {
        pager.setAdapter(new MyPagerAdapter());
        // 加载设置 实现既可以往左滑又可以往右滑
        pager.setCurrentItem(1000000000 / 2);
    }

    /** 初始化数据 **/
    private void initData() {
        // viewpager控件
        pager = (ViewPager) findViewById(R.id.viewpager1);
        // 显示的文本内容
        tv_content = (TextView) findViewById(R.id.tv_content);

        ll_layout = (LinearLayout) findViewById(R.id.ll_layout);
        // 显示小黑点
        list = new ArrayList<ImageView>();
        dots = new ArrayList<View>();
        for (int i = 0; i < picture.length; i++) {
            ImageView iv = new ImageView(getApplicationContext());
            iv.setBackgroundResource(picture[i]);
            // 显示的是图片实际的大小
            // iv.setImageResource(picture[i]);
            list.add(iv);
        }
        /** 初始化小黑点 自己绘制加参数 **/
        for (int i = 0; i < picture.length; i++) {
            // [1]初始化小圆点的view
            View view = new View(getApplicationContext());
            // [2]设置dotView宽和高
            LayoutParams params = new LayoutParams(7, 7);
            params.bottomMargin = 10;
            if (i != 0) {
                params.leftMargin = 7;
            }
            view.setLayoutParams(params);
            view.setBackgroundResource(R.drawable.dot_selector);
            ll_layout.addView(view);
            dots.add(view);
        }
        // 初始化数据时将第一张的文字和小圆点选中
        dot_contentChange(0);
    }

    /** 初始化adapter **/
    public class MyPagerAdapter extends PagerAdapter {
        /** 返回一个极大值实现无限循环 **/
        @Override
        public int getCount() {

            // return list.size();
            return 1000000000;
            // return Integer.MAX_VALUE;

        }

        /**
         * Object:就是在instantiateItem方法里面返回的内容
         */
        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == object;
        }

        /**
         * 初始化条目的内容 类似lsitview getView方法 container:就是viewPager
         * position:每个页面的对应的位置
         */

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            ImageView imageView = list.get(position % 5);

            container.addView(imageView);
            return imageView;
        }

        /**
         * 移除不用的页面 container:viewPager object:就是instantiateItem方法里面的返回值
         */

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {

            container.removeView((View) object);
        }

    }


侧滑菜单

  功能分析:实际上是两个页面 通过一个viewGroup进行包裹 

  menu菜单实际上就是一个scrollView包裹了一个垂直的线性布局,scrollView只能包裹一个孩子.

[1]搭建页面 大家主页面 和 菜单页面

   主页面布局

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/top_bar_bg"
            android:orientation="horizontal" >

            <Button
                android:id="@+id/btn_back"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@drawable/main_back" />

            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingTop="3dp"
                android:src="@drawable/top_bar_divider" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="50dp"
                android:text="黑马新闻"
                android:textColor="#ffffff"
                android:textSize="25sp" />
        </LinearLayout>

          <TextView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:text="钓鱼岛是中国的,\nXXX是世界的"
                android:gravity="center"
                android:textSize="25sp" />

    </LinearLayout>


     菜单页面布局

    <?xml version="1.0" encoding="utf-8"?>
    <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="240dp"
        android:layout_height="match_parent" >

        <LinearLayout
            android:layout_width="240dp"
            android:layout_height="match_parent"
            android:background="@drawable/menu_bg"
            android:orientation="vertical" >

            <TextView
                style="@style/MenuText"
                android:background="#571F2C"
                android:drawableLeft="@drawable/tab_news"
                android:text="新闻" />

            <TextView
                style="@style/MenuText"
                android:drawableLeft="@drawable/tab_read"
                android:text="订阅" />

            <TextView
                style="@style/MenuText"
                android:drawableLeft="@drawable/tab_ties"
                android:text="跟帖" />

            <TextView
                style="@style/MenuText"
                android:drawableLeft="@drawable/tab_pics"
                android:text="图片" />

            <TextView
                style="@style/MenuText"
                android:drawableLeft="@drawable/tab_ugc"
                android:text="话题" />

            <TextView
                style="@style/MenuText"
                android:drawableLeft="@drawable/tab_vote"
                android:text="投票" />

            <TextView
                style="@style/MenuText"
                android:drawableLeft="@drawable/tab_focus"
                android:text="聚合阅读" />
        </LinearLayout>

    </ScrollView>

[2]定义一个viewGroup (slidingMenu) 把我们刚刚定义的布局加到slidingMenu里面

    <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.itheima.slidingmenuhm.SlidingMenu
            android:id="@+id/slidingMenu1"
            android:layout_width="match_parent"
            android:layout_height="match_parent" >

            <!-- 添加自己的孩子  menu菜单和main主界面 -->

            <include layout="@layout/menu" />
            <include layout="@layout/main" />

        </com.itheima.slidingmenuhm.SlidingMenu>

    </RelativeLayout>

[3]由于我定义的slidingmenu继承自相对布局 系统默认实现了测量和排版 所以不需要我们在进行测量 但是我们需要排版,因为系统的排版方式不是我们想要的 所以我们自己重写onLayout方法对孩子进行排版

    //在这个方法里面 自己对孩子进行排版 不使用系统默认的排版方式
        @Override
        protected void onLayout(boolean changed, int l, int t, int r, int b) {

            //[1]找到menu和main孩子 
            View menuView = getChildAt(0);
            View mainView = getChildAt(1);
            //[2]获取菜单的宽度 
            menuWidth = menuView.getMeasuredWidth();
            //[3]对menu菜单进行排版
            menuView.layout(-menuWidth, t, l, b);
            //[4]对main界面排版
            mainView.layout(l, t, r, b);

        }

[4]当用户手指滑动的时候 算出移动的距离 让菜单滑出来 需要我们重写OnTouchEvent方法处理事件

    case MotionEvent.ACTION_DOWN:  //按下
                //[1]获取手指按下的坐标
                downX = event.getX();
                break;

            case MotionEvent.ACTION_MOVE: //移动
                //[2]算出移动的距离 
                float moveX = event.getX();
                distaceX = (int) (moveX - downX)+currentMenuPosition;
                //[3]对边界进行处理
                if (distaceX <= 0) {
                    distaceX = 0;
                }else if (distaceX >=menuWidth) {
                    distaceX = menuWidth;
                }

                //[4]开始滚动view
                startScrollViewContent(distaceX);
                break;

[5]我们自己定义了一个view滚动的方法 让view 的内容进行滚动 因为系统的ScrollTo方法不好用

    /**
         * 由于scrollTo 方法 系统在实现的时候 传入正值往左移动  传入负值往右移动 所以我重写这个方 
         *  符合中国 人的思维
         * @param x
         */
        public void startScrollViewContent(int x){
            super.scrollTo(-x, 0);
        }

[6]处理手指抬起的逻辑 ,当移动的距离<菜单的宽/2 就让菜单回到0 否则把菜单全部显示

    case MotionEvent.ACTION_UP:    //抬起
                //[5]当手指抬起后, 如果移动的距离 < 菜单的宽/2 就回到左边  否则像右移动
                if (distaceX < menuWidth/2) {
                    currentMenuPosition = 0;
                }else {
                    currentMenuPosition = menuWidth;
                }

                //[6]当一段逻辑同时用到多次 我们最好做抽取

                int startX = distaceX; //就是移动的距离
                int endX = currentMenuPosition;
                //[7]实现平滑滚动
                startScroller(startX, endX);

                break;

[7]当menu菜单打开后,我在菜单上向左滑动 发现不能滑动,因为孩子消费了事件,所以我们在slidingmenu(viewGroup)里的onInterceptTouchevent里面处理事件(拦截事件).

        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                 downX = ev.getX();
                 downY = ev.getY();

                break;

            case MotionEvent.ACTION_MOVE:
                float moveX = ev.getX();
                float moveY = ev.getY();
                //[1]算出X轴移动的距离 和 Y移动的距离 
                int distanceX = (int) (moveX - downX);
                int distanceY = (int) (moveY - downY); 
                //[2]如果x轴移动的距离大于Y轴移动的距离 就拦截事件
                if (Math.abs(distanceX) > Math.abs(distanceY)) {
                    return true; 
                }
                break;

            case MotionEvent.ACTION_UP:
                break;
            }

            return super.onInterceptTouchEvent(ev);
        }

[8]点击主页面的按钮判断菜单是否打开或者关闭

    //通过这个方法控制菜单打开或者关闭
        public void setOnMenuIsOpen() {
            int startX = 0;
            if (currentMenuPosition == 0) {
                //说明菜单是关闭状态  需要打开 
                currentMenuPosition = menuWidth;
            }else if (currentMenuPosition == menuWidth) {
                //说明菜单是打开状态  需要关闭
                currentMenuPosition = 0;
                startX = menuWidth;

            }
            //调用平滑滚动的方法
            startScroller(startX, currentMenuPosition);


        }   

2 广告条效果

       使用viewpager实现 直接放到了v4包里,fragment 

       viewpager直接继承ViewGroup 需要往viewpager里面添加孩子.

       viewpager可以让用户左右滑动 和listview相反

       viewpager展示数据的原理和listview一样,   使用自己的适配器展示数据(pagerAdapter)

       使用的步骤

[1]在布局里面声明viewpager

    <android.support.v4.view.ViewPager
            android:id="@+id/vp"
            android:layout_width="match_parent"
            android:layout_height="180dp" >
    </android.support.v4.view.ViewPager>

[2]关联 v4包的源码

     2.1)在libs下创建一个android-support-v4.jar.properties配置文件 

     2.2)配置文件里面的代码如下

     src=D:\\Android\\adt-bundle-windows-x86_64_20140101\\sdk\\extras\\android\\support\\v4\\src

     2.3)关闭工程在打开工程即可

[3]创建viewpager的适配器

    //创建viewpager需要的适配器
        class MyPagerAdapter extends PagerAdapter{

            //展示viewpager条目的数量
            @Override
            public int getCount() {
                return ivs.size();
            }

            /**
             * Object:就是在instantiateItem方法里面返回的内容
             */
            @Override
            public boolean isViewFromObject(View view, Object object) {
                return view == object;
            }

            /**
             * 初始化条目的内容  类似lsitview getView方法
             * container:就是viewPager
             * position:每个页面的对应的位置
             */
            @Override
            public Object instantiateItem(ViewGroup container, int position) {
                //[1]根据位置 去集合里面取数据 
                ImageView iv = ivs.get(position);
                //[2]获取到每个iv后加入到viewpager中
                container.addView(iv);
                return iv;
            }

            /**
             * 移除不用到页面
             * container:viewPager 
             * object:就是instantiateItem方法里面的返回值
             */
            @Override
            public void destroyItem(ViewGroup container, int position, Object object) {
                container.removeView((View) object);
            }


        }

[4]添加小圆点的布局

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignBottom="@id/vp"
            android:background="#66000000"
            android:gravity="center_horizontal"
            android:orientation="vertical"
            android:paddingBottom="5dp"
            android:paddingTop="5dp" >

            <TextView
                android:id="@+id/tv_content"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="我是小圆点对应的内容"
                android:textColor="#ffffff"
                android:textSize="17sp" />
            <!-- 动态的往布局里面添加小圆点 -->

            <LinearLayout
                android:id="@+id/ll_layout"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="4dp"
                android:orientation="horizontal" >

                <!-- <View
                    android:layout_width="5dp"
                    android:layout_height="5dp"
                    android:background="@drawable/dot_selector" /> -->
            </LinearLayout>
        </LinearLayout>

[5]给viewpager设置页面滚动的监听

    //代表viewpager的监听
        OnPageChangeListener listener = new OnPageChangeListener() {

            //当一个新的页面被选中的时候调用
            @Override
            public void onPageSelected(int position) {

                changeDotstateAndText(position);

            }

            //当页面开始滚动
            @Override
            public void onPageScrolled(int position, float positionOffset,
                    int positionOffsetPixels) {

            }
            //当滑动页面的状态改变的时候调用
            @Override
            public void onPageScrollStateChanged(int state) {

            }
        };

[6]动态改变小圆点状态和对应文本的内容 由于2个地方都需要改变小圆点的状态和对应的内容 所以我们抽出一个方法

    /**改变小圆点的状态和对应文本的内容**/
        private void changeDotstateAndText(int position) {
            //[1]动态改变小圆点的文本内容  数据在哪里存着就去哪里取
            tv_content.setText(descs[position]);

            if (currentDotView!=null) {
                currentDotView.setSelected(false);
            }
            //[2]更新小圆点的状态  小圆点在集合里面存着 
            dotLists.get(position).setSelected(true);

            //[3]把dotLists.get(position)赋值给currentDotView
            currentDotView = dotLists.get(position);
        }

[7]实现viewpager的无限循环

        0 % 5 = 0

        1 % 5 = 1

        2 %5 =2

        3 %5=3;

        4%5=4

        5%5 = 0 

        6%5 = 1

        7%5=2 .......

        就是在适配器的getcount方法里面返回一个比较大的数就可以了 把position对5取%

[8]实现自动切换

      在onStart方法里面使用handler发一个消息 

    //当界面可见的时候执行 
        @Override
        protected void onStart() {
            //4秒钟后 显示下一个页面的内容
            handler.sendEmptyMessageDelayed(10, 4000);
            super.onStart();
        }


      在handlermessage方法里面处理消息

    private Handler handler = new Handler(){
            //处理消息
            public void handleMessage(android.os.Message msg) {
                //显示viewpager下个页面的内容 
                vp.setCurrentItem(vp.getCurrentItem()+1);
                handler.sendEmptyMessageDelayed(10, 4000);
            };
        };

[9]当viewpager初始化的时候既可以往左滑动,又可以往又滑动

    1.vp.setCurrentItem(vpMaxSize/2);                   

作者:yin13753884368 发表于2016/11/18 20:12:00 原文链接
阅读:35 评论:0 查看评论

Viewing all articles
Browse latest Browse all 5930

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>