Android 自定义控件

自定义控件
旋转动画工具类

package com.gordon.youku;

import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;

/**
 * Created by Kevin.
 */

public class AnimUtils {

    //利用重载, 可以在不改变原来api的情况下, 增添新的参数
    public static void show(ViewGroup view) {
        show(view, 0);
    }

    public static void hide(ViewGroup view) {
        hide(view, 0);
    }

    //隐藏, 旋转动画
    public static void hide(ViewGroup view, long delay) {
        //围绕底边中心点旋转
        RotateAnimation anim = new RotateAnimation(0, 180, Animation.RELATIVE_TO_SELF, 0.5f,
                Animation.RELATIVE_TO_SELF, 1);
        anim.setDuration(500);
        anim.setFillAfter(true);//动画结束后保持住当时状态
        anim.setStartOffset(delay);//延时多长时间之后再启动动画
        view.startAnimation(anim);

        //禁用所有按钮的点击事件
        int childCount = view.getChildCount();//子控件个数
        for (int i = 0; i < childCount; i++) {
            View child = view.getChildAt(i);//获取第i个子控件
            child.setEnabled(false);//禁用
        }

    }

    //显示, 旋转动画
    public static void show(ViewGroup view, long delay) {
        //围绕底边中心点旋转
        RotateAnimation anim = new RotateAnimation(180, 360, Animation.RELATIVE_TO_SELF, 0.5f,
                Animation.RELATIVE_TO_SELF, 1);
        anim.setDuration(500);
        anim.setFillAfter(true);//动画结束后保持住当时状态
        anim.setStartOffset(delay);//延时多长时间之后再启动动画
        view.startAnimation(anim);

        //启用所有按钮的点击事件
        int childCount = view.getChildCount();//子控件个数
        for (int i = 0; i < childCount; i++) {
            View child = view.getChildAt(i);//获取第i个子控件
            child.setEnabled(true);//启用
        }
    }
}

主函数

package cn.itcast.youku11;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.KeyEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private ImageView ivHome;
    private ImageView ivMenu;

    private RelativeLayout rlLevel1;
    private RelativeLayout rlLevel2;
    private RelativeLayout rlLevel3;

    private boolean isLevel3Show = true;//标记布局是否显示
    private boolean isLevel2Show = true;//标记布局是否显示
    private boolean isLevel1Show = true;//标记布局是否显示

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ivHome = (ImageView) findViewById(R.id.iv_home);
        ivMenu = (ImageView) findViewById(R.id.iv_menu);
        rlLevel1 = (RelativeLayout) findViewById(R.id.rl_level1);
        rlLevel2 = (RelativeLayout) findViewById(R.id.rl_level2);
        rlLevel3 = (RelativeLayout) findViewById(R.id.rl_level3);

        ivHome.setOnClickListener(this);
        ivMenu.setOnClickListener(this);

        //如果给第三层布局加点击事件, 会导致home和menu按钮无法点击
        //解决办法: 将第三层布局写在最底下, 第一层写在最上面, 就不会挡住点击事件了
        rlLevel3.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.iv_home:
                System.out.println("home clicked!!!");
                //如果显示则隐藏;反之亦然
                if (isLevel2Show) {
                    AnimUtils.hide(rlLevel2);
                    isLevel2Show = false;

                    //如果level3显示, 也要隐藏
                    if (isLevel3Show) {
                        AnimUtils.hide(rlLevel3, 200);
                        isLevel3Show = false;
                    }
                } else {
                    AnimUtils.show(rlLevel2);
                    isLevel2Show = true;
                }

                break;
            case R.id.iv_menu:
                System.out.println("menu clicked!!!");
                //如果显示则隐藏;反之亦然
                if (isLevel3Show) {
                    AnimUtils.hide(rlLevel3);
                    isLevel3Show = false;
                } else {
                    AnimUtils.show(rlLevel3);
                    isLevel3Show = true;
                }

                break;

            default:
                break;
        }
    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
    }

    //拦截物理按键
    //拦截不了: home键, 电源键
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        System.out.println("当前按键:" + keyCode);

        //物理菜单键
        if (keyCode == KeyEvent.KEYCODE_MENU) {
            if (isLevel1Show) {
                AnimUtils.hide(rlLevel1);
                isLevel1Show = false;

                if (isLevel2Show) {
                    AnimUtils.hide(rlLevel2, 200);
                    isLevel2Show = false;
                }

                if (isLevel3Show) {
                    AnimUtils.hide(rlLevel3, 300);
                    isLevel3Show = false;
                }

            } else {
                AnimUtils.show(rlLevel1);
                AnimUtils.show(rlLevel2, 200);

                isLevel1Show = true;
                isLevel2Show = true;
            }

            return true;//表示已经处理完事件
        }

        return super.onKeyDown(keyCode, event);
    }
}

效果
在这里插入图片描述
**点击事件bug 动画只是假象,点击事件依然存在 **

        //禁用所有按钮的点击事件
        int childCount = view.getChildCount();//子控件个数
        for (int i = 0; i < childCount; i++) {
            View child = view.getChildAt(i);//获取第i个子控件
            child.setEnabled(false);//禁用
        }

07 ViewPager的使用

在这里插入代码片

08 ViewPager循环滑动效果

效果1:
        @Override
        public int getCount() {
            //return mImageIds.length;
            return Integer.MAX_VALUE;
        }

        //初始化条目布局对象,类似getView
        @NonNull
        @Override
        public Object instantiateItem(@NonNull ViewGroup container, int position) {
            //当前位置对集合大小取余,返回0-4的位置信息
            position = position % mImageIds.length;
            //初始化条目布局
            ImageView imageView = new ImageView(MainActivity.this);
            imageView.setImageResource(mImageIds[position]);
            //将条目布局添加给viewpager
            container.addView(imageView);
            System.out.println("初始化条目:" + position);
            //返回布局对象
            return imageView;
        }

效果2:
        //设置开始时左右都能滑
        mViewPager.setCurrentItem(Integer.MAX_VALUE/2);
        mViewPager.setCurrentItem(mImageIds.length*100000);

09.广告条加标题栏

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="180dp">

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

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#a000"
            android:orientation="vertical"
            android:layout_gravity="bottom"
            android:padding="5dp">

            <TextView
                android:id="@+id/tv_title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="标题" />
        </LinearLayout>

    </FrameLayout>

        mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float posOffset, int posOffsetPixels) {}

            @Override
            public void onPageSelected(int position) {
                position = position % mImageIds.length;
                tvTitle.setText(mImageDes[position]);
            }

            @Override
            public void onPageScrollStateChanged(int state) {}
        });
        tvTitle.setText(mImageDes[0]);

10.小圆点逻辑处理

布局:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">

    <solid android:color="#f00" />
    <size
        android:width="5dp"
        android:height="5dp" />
</shape>

        //动态初始化小圆点
        for (int i = 0; i < mImageIds.length; i++) {
            ImageView imageView = new ImageView(this);
            imageView.setImageResource(R.drawable.shape_gray);
            //动态设置边距
            LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
            //从第二个点设置边距
            if (i > 0) {
                lp.leftMargin = 10;
            }
            imageView.setLayoutParams(lp);
            //将小圆点添加到线性布局(5个小圆点)
            llContainer.addView(imageView);
        }

            @Override
            public void onPageSelected(int position) {
                position = position % mImageIds.length;
                tvTitle.setText(mImageDes[position]);

                for (int i = 0; i < mImageIds.length; i++) {
                    ImageView image = (ImageView) llContainer.getChildAt(i);
                    if (i != position) {
                        image.setImageResource(R.drawable.shape_gray);
                    } else {
                        image.setImageResource(R.drawable.shape_red);
                    }
                }
                //切换红点图片
                ImageView imageView = (ImageView) llContainer.getChildAt(position);
                imageView.setImageResource(R.drawable.shape_red);
            }

11.广告条自动轮播效果


    private Handler mHandler = new Handler() {

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);

            //切换到下个页面
            int currentItem = mViewPager.getCurrentItem();
            currentItem++;
            mViewPager.setCurrentItem(currentItem);

            mHandler.sendEmptyMessageDelayed(0,3000);
        }
    };

        mHandler.sendEmptyMessageDelayed(0, 3000);

12.广告条触摸响应

按住停止自动发消息,抬起时继续发消息
        mViewPager.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        //停止轮播
                        mHandler.removeCallbacksAndMessages(null);
                        break;
                    case MotionEvent.ACTION_UP:
                        mHandler.sendEmptyMessageDelayed(0,3000);
                        break;
                    case MotionEvent.ACTION_MOVE:
                        break;
                }
                return false;
            }
        });

完整代码

package com.gordon.viewpager;

import android.os.Handler;
import android.os.Message;
import android.support.annotation.NonNull;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    private final String[] mImageDes = {"巩俐不低俗,我就不能低俗", "朴树又回来啦!再唱经典老歌引万人大合唱", "揭秘北京电影如何升级",
            "乐视网TV版大派送", "热血屌丝的反杀"};

    private final int[] mImageIds = new int[]{R.drawable.a, R.drawable.b, R.drawable.c, R
            .drawable.d, R.drawable.e};

    private ViewPager mViewPager;
    private TextView tvTitle;
    private LinearLayout llContainer;
    private ImageView imageView;

    private Handler mHandler = new Handler() {

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);

            //切换到下个页面
            int currentItem = mViewPager.getCurrentItem();
            currentItem++;
            mViewPager.setCurrentItem(currentItem);

            mHandler.sendEmptyMessageDelayed(0, 3000);
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tvTitle = findViewById(R.id.tv_title);
        llContainer = findViewById(R.id.ll_container);

        mViewPager = findViewById(R.id.view_pager);
        MyAdapter myAdapter = new MyAdapter();
        mViewPager.setAdapter(myAdapter);

        //设置开始时左右都能滑
        mViewPager.setCurrentItem(Integer.MAX_VALUE / 2);
        mViewPager.setCurrentItem(mImageIds.length * 100000);

        mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {

            @Override
            public void onPageScrolled(int position, float posOffset, int posOffsetPixels) {

            }

            @Override
            public void onPageSelected(int position) {
                position = position % mImageIds.length;
                tvTitle.setText(mImageDes[position]);

                for (int i = 0; i < mImageIds.length; i++) {
                    ImageView image = (ImageView) llContainer.getChildAt(i);
                    if (i != position) {
                        image.setImageResource(R.drawable.shape_gray);
                    } else {
                        image.setImageResource(R.drawable.shape_red);
                    }
                }
                //切换红点图片
                ImageView imageView = (ImageView) llContainer.getChildAt(position);
                imageView.setImageResource(R.drawable.shape_red);
            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });
        tvTitle.setText(mImageDes[0]);

        //动态初始化小圆点
        for (int i = 0; i < mImageIds.length; i++) {
            imageView = new ImageView(this);
            imageView.setImageResource(R.drawable.shape_gray);
            //动态设置边距
            LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
            //从第二个点设置边距
            if (i > 0) {
                lp.leftMargin = 10;
                imageView.setImageResource(R.drawable.shape_gray);
            } else {
                imageView.setImageResource(R.drawable.shape_red);
            }
            imageView.setLayoutParams(lp);
            //将小圆点添加到线性布局(5个小圆点)
            llContainer.addView(imageView);
        }

        mHandler.sendEmptyMessageDelayed(0, 3000);

        mViewPager.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        //停止轮播
                        mHandler.removeCallbacksAndMessages(null);
                        break;
                    case MotionEvent.ACTION_UP:
                        mHandler.sendEmptyMessageDelayed(0,3000);
                        break;
                    case MotionEvent.ACTION_MOVE:
                        break;
                }
                return false;
            }
        });
    }

    class MyAdapter extends PagerAdapter {

        public MyAdapter() {}

        @Override
        public int getCount() {
            //return mImageIds.length;
            return Integer.MAX_VALUE;
        }

        //判断显示的view是不是就是返回的object对象,只有是true,才显示,否则不显示
        @Override
        public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
            return view == object;
        }

        //初始化条目布局对象,类似getView
        @NonNull
        @Override
        public Object instantiateItem(@NonNull ViewGroup container, int position) {
            //当前位置对集合大小取余,返回0-4的位置信息
            position = position % mImageIds.length;
            //初始化条目布局
            ImageView imageView = new ImageView(MainActivity.this);
            imageView.setImageResource(mImageIds[position]);
            //将条目布局添加给viewpager
            container.addView(imageView);
            System.out.println("初始化条目:" + position);
            //返回布局对象
            return imageView;
        }

        //销毁布局对象
        @Override
        public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
            //删掉,底层扔了异常
            //super.destroyItem(container, position, object);
            container.removeView((ImageView) object);
            System.out.println("销毁条目:" + position);
        }
    }
}

布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="180dp">

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

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom"
            android:background="#a000"
            android:orientation="vertical"
            android:padding="5dp">

            <TextView
                android:id="@+id/tv_title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="标题" />
            <LinearLayout
                android:id="@+id/ll_container"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_horizontal"
                android:orientation="horizontal">
            </LinearLayout>
        </LinearLayout>
    </FrameLayout>
</LinearLayout>

13.下拉框效果实现

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />

    <RelativeLayout
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true">

        <EditText
            android:id="@+id/et_text"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <ImageView
            android:id="@+id/iv_drop"
            android:layout_width="wrap_content"
            android:layout_alignParentRight="true"
            android:src="@drawable/down_arrow"
            android:layout_height="wrap_content" />

    </RelativeLayout>

</RelativeLayout>

    private ListView listView = new ListView(this);
    private EditText etText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        etText = findViewById(R.id.et_text);

        findViewById(R.id.iv_drop).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                showPopup();
            }
        });
    }

    private void showPopup() {
        listView.setBackgroundResource(R.drawable.listview_background);
        PopupWindow popupWindow = new PopupWindow(listView, etText.getWidth(), 200, true);
        popupWindow.showAsDropDown(etText, 0, 0);
    }

自定义控件切换按钮

package cn.itcast.switch11;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;

/**
 * 控件绘制流程:
 * <p>
 * 1. measure方法来确定控件尺寸
 * 2. layout方法确定控件位置
 * 3. draw方法绘制控件内容
 * <p>
 * measure->layout->draw
 * onMeasure->onLayout->onDraw
 *
 * 1280x720  xhdpi
 * 480x800 hdpi
 */
public class MySwitch extends View {

    private Paint paint;

    private Bitmap mBitmapBg;
    private Bitmap mBitmapSlide;

    private int MAX_LEFT;//最大左边距

    private int mSlideLeft;//当前左边距

    private boolean isOpen = false;//当前开关状态

    public MySwitch(Context context) {
        this(context, null);
    }

    public MySwitch(Context context, AttributeSet attrs) {
        this(context, attrs, -1);
    }

    public MySwitch(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        paint = new Paint();
        paint.setColor(Color.RED);

        //初始化背景图片
        mBitmapBg = BitmapFactory.decodeResource(getResources(), R.drawable.switch_background);
        //滑块图片
        mBitmapSlide = BitmapFactory.decodeResource(getResources(), R.drawable.slide_button);

        MAX_LEFT = mBitmapBg.getWidth() - mBitmapSlide.getWidth();

        //设置点击事件
        this.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if(isOpen) {
                    mSlideLeft = 0;
                    isOpen = false;
                }else {
                    mSlideLeft = MAX_LEFT;
                    isOpen = true;
                }

                //刷新当前控件
                invalidate();//此方法会导致onDraw重新走一遍
            }
        });
    }

    //重写此方法可以修改控件尺寸
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //setMeasuredDimension(100, 100);
        setMeasuredDimension(mBitmapBg.getWidth(), mBitmapBg.getHeight());
        System.out.println("onMeasure....");
    }

    //设置控件位置
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);

        System.out.println("onLayout....");
    }

    //绘制控件
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //canvas.drawRect(0, 0, 200, 200, paint);
        System.out.println("onDraw......");

        //在左上角绘制图片
        canvas.drawBitmap(mBitmapBg, 0, 0, null);
        canvas.drawBitmap(mBitmapSlide, mSlideLeft, 0, null);
    }
}

自定义SeekBar

mClipPath.addRoundRect

https://blog.csdn.net/weixin_34130389/article/details/91397621

ValueAnimator.ofInt
https://blog.csdn.net/songkai0825/article/details/89367666

定时器

https://www.oschina.net/question/2447911_2176528

xml一半圆角

https://blog.csdn.net/jdsjlzx/article/details/46989023

float[] radii={12f,12f,0f,0f,0f,0f,0f,0f};
path.addRoundRect(new RectF(0, 0, 50, 50), radii, Path.Direction.CW);canvas.drawPath(path,paint);

自定义seekbar

https://github.com/525642022/MyCustomSeekBar

https://github.com/zhangliangming/SeekBar/blob/master/seekbarlibrary/src/main/java/com/zlm/libs/widget/CustomSeekBar.java

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值