Android-装B必备自定义View(1)

转载请标明出处:

http://blog.csdn.net/hai_qing_xu_kong/article/details/52186398

本文出自:【顾林海的博客】

前言

已经好长时间没更新博客了,今天给大家带来一个横向滚动的菜单,用的是HorizontalScrollView,但HorizontalScrollView不能在滚动时定位到某个菜单,因此监听了onScrollChanged方法,代码比较简单,大家看代码就行了,主要是封装了一下,方便大家使用,项目github在底部会给出的。废话不多说,先上效果图:

怎么用

这个控件已经进行了非常给力的封装了,想必大家一定用的比较酸爽。

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

    <com.horizontalscrollview.view.HorizontalScrollMenuView
        android:id="@+id/hs_menu"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/white"
        android:layout_centerVertical="true"/>

</RelativeLayout>
package com.horizontalscrollview;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.horizontalscrollview.view.HorizontalScrollMenuView;
import com.horizontalscrollview.view.adapter.BaseMenuAdapter;

public class MainActivity extends AppCompatActivity {

    private int[] mDrawableId={R.drawable.image1,R.drawable.image3,R.drawable.image3};
    private String[] mTitle={"菜单一","菜单二","菜单三"};

    private HorizontalScrollMenuView mHorizontalScrollMenuView;
    private MyMenuAdapter mMyMenuAdapter;

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

    private void initViews(){
        mHorizontalScrollMenuView= (HorizontalScrollMenuView) findViewById(R.id.hs_menu);
        mMyMenuAdapter=new MyMenuAdapter();
        mHorizontalScrollMenuView.setAdapter(mMyMenuAdapter);
        mHorizontalScrollMenuView.notifyDataSetChanged();
    }

    class MyMenuAdapter extends BaseMenuAdapter{
        @Override
        public int getCount() {
            return mTitle.length;
        }

        @Override
        public View getView(final int position) {
            View root= LayoutInflater.from(MainActivity.this).inflate(R.layout.menu_layout,null);
            ImageView imageView= (ImageView) root.findViewById(R.id.iv_icon);
            TextView tv_title= (TextView) root.findViewById(R.id.tv_title);
            tv_title.setText(mTitle[position]);
            imageView.setImageResource(mDrawableId[position]);
            imageView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Toast.makeText(MainActivity.this,"点击了"+mTitle[position],Toast.LENGTH_SHORT).show();
                }
            });
            return root;
        }

        @Override
        public int getViewWidth() {
            return 250;
        }
    }

}

用法已经贴出来了,下面有兴趣的话看看源码,没兴趣的话,我也没辙,呵呵。。。

装B源码

package com.horizontalscrollview.view.adapter;

import android.view.View;

/**
 * Created by glh on 2016-08-11.
 */
public interface MenuAdapter {
    int getCount();
    View getView(int position);
}
package com.horizontalscrollview.view.adapter;

import android.util.SparseArray;
import android.view.View;

/**
 * 菜单的抽象类,用户子菜单View的保存
 * Created by glh on 2016-08-11.
 */
public abstract class BaseMenuAdapter implements MenuAdapter{

    private SparseArray<View> mMenuArray=new SparseArray<>();

    /**
     * 获取子View的宽度,必传
     * @return
     */
    public abstract int getViewWidth();

    public SparseArray<View> getView(){
        mMenuArray.clear();
        for(int index=0,length=getCount();index<length;index++){
            mMenuArray.append(index,getView(index));
        }
        return mMenuArray;
    }

}
package com.horizontalscrollview.view;

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;

import com.horizontalscrollview.R;
import com.horizontalscrollview.util.DensityUtil;
import com.horizontalscrollview.view.adapter.BaseMenuAdapter;

/**
 * 水平滚动的菜单
 * Created by glh on 2016-08-11.
 */
public class HorizontalScrollMenuView extends RelativeLayout{

    private Context mContext;

    private View mRootView;
    private LinearLayout ll_menu;//菜单容器
    private ObservableHorizontalScrollView mObservableHorizontalScrollView;//滚动容器
    private int mMenuIndex;
    private int mScroll;
    private int interval;//菜单最左边和最右边的距离
    private int mMiddle;//菜单间隔距离
    private int mViewWidth;//菜单宽度
    private MyHandler mMyHandler;
    private BaseMenuAdapter mBaseMenuAdapter;

    public HorizontalScrollMenuView(Context context) {
        this(context, null);

    }

    public HorizontalScrollMenuView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public HorizontalScrollMenuView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.mContext=context;
        mMyHandler=new MyHandler();
        interval=(DensityUtil.getWindowWidth(mContext) - DensityUtil.dip2px(250)) / 2;
        mMiddle=DensityUtil.dip2px(25);
        mViewWidth=DensityUtil.dip2px(250);
        initView();
        initEvent();
    }

    private void initView(){
        mRootView= LayoutInflater.from(mContext).inflate(R.layout.horizontal_scroll_layout,this,true);
        ll_menu= (LinearLayout) mRootView.findViewById(R.id.ll_menu);
        mObservableHorizontalScrollView= (ObservableHorizontalScrollView) mRootView.findViewById(R.id.obh_view);
    }

    /**
     * 添加菜单
     */
    private void addMenu(){
        ll_menu.removeAllViews();
        SparseArray<View> viewSparseArray=mBaseMenuAdapter.getView();
        View intervalView;
        for(int index=0,length=viewSparseArray.size();index<length;index++){
            if (index == 0) {
                /**
                 * <p>
                 *     在最左边增加一个(屏宽-菜单宽)/2的宽度的View,
                 *     目的在于使第一个菜单居中显示。
                 * </>
                 */
                intervalView = new View(mContext);
                intervalView.setLayoutParams(new LayoutParams(interval, 1));
                ll_menu.addView(intervalView);
            }
            ll_menu.addView(viewSparseArray.get(index));
            if (index == length-1) {
                /**
                 * <p>
                 *     在最右边增加一个(屏宽-菜单宽)/2的宽度的View,
                 *     目的在于使最后一个菜单居中显示。
                 * </>
                 */
                intervalView = new View(mContext);
                intervalView.setLayoutParams(new LayoutParams(interval, 1));
                ll_menu.addView(intervalView);
            }else{
                /**
                 * 两个菜单之间留一点空隙
                 */
                intervalView = new View(mContext);
                intervalView.setLayoutParams(new LayoutParams(mMiddle, 1));
                ll_menu.addView(intervalView);
            }
        }
    }

    private void initEvent(){
        mObservableHorizontalScrollView.setHorizontalScrollViewListener(new ObservableHorizontalScrollView.HorizontalScrollViewListener() {
            @Override
            public void onScrollChanged(ObservableHorizontalScrollView scrollView,
                                        int x, int y, int oldx, int oldy) {
                mMenuIndex = x / mViewWidth;//计算当前位置
                mScroll = x % mViewWidth;
                if (mScroll >= 0.5) {
                    mMenuIndex++;
                }
                if (oldx - x > 0) {
                    /**
                     * 菜单往右滑动
                     */
                    mMenuIndex--;
                }

            }
        });

        mObservableHorizontalScrollView.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_UP:
                        mMyHandler.sendEmptyMessage(0);
                        break;
                    default:
                        break;
                }
                return false;
            }
        });
    }

    /**
     * 设置View
     * @param adapter
     */
    public void setAdapter(BaseMenuAdapter adapter){
        this.mBaseMenuAdapter=adapter;
        this.interval =(DensityUtil.getWindowWidth(mContext) - DensityUtil.dip2px(mBaseMenuAdapter.getViewWidth())) / 2;
        this.mViewWidth=DensityUtil.dip2px(mBaseMenuAdapter.getViewWidth());
    }

    /**
     * 刷新
     */
    public void notifyDataSetChanged(){
        addMenu();
    }

    /**
     * 设置菜单间隔
     * @param middle
     */
    public void setMiddle(int middle){
        mMiddle=DensityUtil.dip2px(middle);
    }

    class MyHandler extends Handler {
        public MyHandler() {
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 0:
                    mObservableHorizontalScrollView.smoothScrollTo(mMenuIndex * (mViewWidth + mMiddle), 0);
                    break;
            }
        }
    }

}

项目地址(豪华套餐)

以下是完整的github项目地址

github项目源码地址:点击【项目源码】

时间: 2024-07-28 15:57:58

Android-装B必备自定义View(1)的相关文章

Android 如何 画 柱状图 -------自定义View

实现了 柱状图 根据 SeekBar的滑动 改变的效果: 图示效果: 自定义View的代码: package com.example.coustomviewdemo; import android.R.color; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.g

Android属性动画与自定义View——实现vivo x6更新系统的动画效果

晚上好,现在是凌晨两点半,然后我还在写代码.电脑里播放着<凌晨两点半>,晚上写代码,脑子更清醒,思路更清晰. 今天聊聊属性动画和自定义View搭配使用,前面都讲到自定义View和属性动画,但是一起用的还是不多,刚巧今晚手机提示我更新系统,我看到那个更新的动画还不错,仔细的分析了一下,于是我也决定写一个,不是一模一样的,但是效果和原理是一样的. 先看看图: 这是一张静态的图,这里有三个波浪线,当下载完之后,波浪线会往上活动,一直到消失. 所以难点也是在这个波浪线上.这个波浪线类似于一个水波纹,也

Android应用开发之自定义View触摸相关工具类全解

背景 最近有些乱,各种事情,各种交叉.好在还有一点上进心,于是继续将自定义这个系列的核心知识再梳理一下吧.关于自定义控件前面博文说过了,这里不会教你拿来主义,只授之以渔,如果你喜欢拿来主义,不好意思,请绕行,如果你喜欢得渔,那请继续. 前面我们已经叙述过了几篇关于自定义View涉及的东西,大家可以自己回过头去看我之前的博客,譬如事件处理.坐标系.工具类等.下面我们还是继续补充一些常用的自定义控件工具类. [工匠若水 http://blog.csdn.net/yanbober 未经允许严禁转载,请

Android 高手进阶之自定义View,自定义属性(带进度的圆形进度条)

转载请注明地址:http://blog.csdn.net/xiaanming/article/details/10298163 很多的时候,系统自带的View满足不了我们功能的需求,那么我们就需要自己来自定义一个能满足我们需求的View,自定义View我们需要先继承View,添加类的构造方法,重写父类View的一些方法,例如onDraw,为了我们自定义的View在一个项目中能够重用,有时候我们需要自定义其属性,举个很简单的例子,我在项目中的多个界面使用我自定义的View,每个界面该自定义View

Android知识梳理之自定义View

虽然android本身给我们提供了形形色色的控件,基本能够满足日常开发的需求,但是面对日益同质化的app界面,和不同的业务需求.我们可能就需要自定义一些View来获得比较好的效果.自定义View是android开发者走向高级开发工程师必须要走的一关. 转载请标明出处:http://blog.csdn.net/unreliable_narrator/article/details/51274264 一,构造函数: 当我们创建一个类去继承View的时候,会要求我们至少去实现一个构造函数. publi

Android ——利用OnDraw实现自定义View(转)

自定义View的实现方式大概可以分为三种,自绘控件.组合控件.以及继承控件.本文将介绍自绘控件的用法.自绘控件的意思是,这个控件上的内容是用onDraw函数绘制出来的.关于onDraw函数的介绍可参看 Android视图绘制流程完全解析,带你一步步深入了解View(二) . 例子1:在layout文件中使用自绘控件 出处:http://blog.csdn.net/guolin_blog/article/details/17357967 下面我们准备来自定义一个计数器View,这个View可以响应

【Android 应用开发】 自定义 View 组件 -- 圆形进度条

转载著名出处 : http://blog.csdn.net/shulianghan/article/details/40351487 代码下载 : -- CSDN 下载地址 : http://download.csdn.net/detail/han1202012/8069497 ; -- GitHub 地址 : https://github.com/han1202012/CircleProcess.git ; -- 工程示例 : 一. 相关知识点解析 1. 自定义 View 组件构造方法 构造方

Android Matrix手势缩放自定义view 不止于Imageview

转载请注明出处:http://blog.csdn.net/coderyue/article/details/51397409 之前写过一篇文章Android TextView 横竖排切换(字方向不变) 是自定义了一个LinearLayout, 实现了当然还不够, 还要对它进行操作, 平移,旋转 and 缩放, 相信很多小伙伴都知道对图片的平移等等操作最好用的就是矩阵了,因为有个方法叫做imageview.setImageMatrix(matrix), 直接构造一个矩阵对象然后设置到图片上就进行相

Android 用属性动画自定义view的渐变背景

自定义view渐变背景,同时监听手势自动生成小圆球. 宿主Activity如下: package com.edaixi.tempbak; import java.util.ArrayList; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ArgbE