资讯

精准传达 • 有效沟通

从品牌网站建设到网络营销策划,从策略到执行的一站式服务

android仿,android仿微信聊天界面

Android仿ios条件选择器pickerview

最近怎么老写View,可能写view比较方便,写其它东西还要抽时间整理总结,写View就直接封完写出来就行。

成都创新互联凭借专业的设计团队扎实的技术支持、优质高效的服务意识和丰厚的资源优势,提供专业的网站策划、网站设计、成都网站建设、网站优化、软件开发、网站改版等服务,在成都十年的网站建设设计经验,为成都1000+中小型企业策划设计了网站。

准备国庆放假,无心工作,那就写篇简单实用一点的文章,总不能白白浪费了时间。

有时候ios端会用到条件选择器,好像是那边自带的,而android这边是没有的,但是为了两端统一,没办法,只能我们去迁就他们了(你让一个有自带的去写自定义是基本不可能的事)。

最经典的是我们有选择地址的需求,比如美团这里的:

这个android是原生是没有的,只有能选择日期的。那怎么办?自定义,好像略难,那就用三方的吧。

我找了很多,就觉得这个库是做得比较好,比较完整的,而且也一直有在维护,还是比较推荐,使用起来也比较方便。项目里有很清晰的文档,建议看之前先浏览过文档。

我使用的效果:

我还是顺便把源码也浏览了下。发现这里有3个比较重要的类,这个之后会简单的介绍:

(1)WheelView

(2)条件选择的WheelOptions, 我感觉这个类的封装有点vm的意思

(3)最外层封装的OptionsPickerView

如果只是为了选择地址的话直接用它封装好的就行,但是有时候可能会需要用到其它的布局或需求,那我们就要在它原有的功能上进行扩展,比如说我写的这个时间段的现在,直接用是没有的,需要自己扩展。

而要进行扩展的话,就要先浏览源码看看它内部怎么写的。

可以从调用的地方找到OptionsPickerView类

然后看看OptionsPickerView类内部,你会发现很多方法,但是基本都是builder方法个getset方法,我们可以找到重要的几个方法。

这里做的是为view设置属性。重要的是这里

这里的意思就是把这个View给WheelOptions这个对象,让它来做处理。然后可以看

看布局。

可以看出它里面是写死固定就是3列。其实我不太赞成这样的做法,对于这样的多情况view的封装,我个人还是比较喜欢做动态的。由于这里固定是3列,所以我上图中4列的情况直接使用是实现不了的,所以需要扩展。这里的WheelView就是单列

它这里布局写死了固定3列,那我肯定是没法复用它的这个布局了,所以就只能重写布局。

我只写了LinearLayout,就是要动态去添加WheelView。

原本的OptionsPickerView中

在builder构造时就固定了布局,所以我这不好扩展,不如重写一个OptionsPickerView,当然重写Builder也行,但是我觉得重写OptionsPickerView比较好。而且他原本只有两个类

所以我们需要继承BasePickerView重写一个PickerView,他原本内部的逻辑没问题,我就抄过来用好了。

修改了

(1)修改布局变成我的布局

(2)然后把创建WheelView给加扩展createWheel(optionsPicker, context, total);因为我不想每次都都写Builder这么多参数,我把这个pickerview当成中间成来弄,让子类继承它来做简单的扩展

我们重写个WheelView,因为原本的WheelView是做固定3列的处理,我们需要做成个动态的。

(1)我多添加了个参数total表示要展示多少列

(2)用ListWheelView wvList数组来动态创建添加WheelView

(3)用ListListT items 来装每一列的数据(我这个Wheel只做了不关联情况下的多列,关联情况下我没弄)

(4)showWheelView();

这个方法做展示的规则,默认是平均展示total列,而如果需要做特殊的展示情况,像我上边一样的,就写个类继承这个类重新这个方法重新展示的规则就行,比如我的时间期间选择器。

重写这个方法就能展示出自己需要展示的效果

调用时也很方便。

我讲这篇的目的是为了第一介绍一下这个三方库,还是比较实用的。第二,说下扩展的重要性。第三,放假了实在工作效率低。

Android 自定义仿京东地址选择器

public class AddressPickerViewextends RelativeLayout{

// recyclerView 选中Item 的颜色

private int defaultSelectedColor = Color.parseColor("#3D71FF");

// recyclerView 未选中Item 的颜色

private int defaultUnSelectedColor = Color.parseColor("#2c2c2c");

// 确定字体不可以点击时候的颜色

private int defaultSureUnClickColor = Color.parseColor("#7F7F7F");

// 确定字体可以点击时候的颜色

private int defaultSureCanClickColor = Color.parseColor("#3D71FF");

private ContextmContext;

private int defaultTabCount =3; //tab 的数量

private TabLayoutmTabLayout; // tabLayout

private RecyclerViewmRvList; // 显示数据的RecyclerView

private StringdefaultProvince ="省份"; //显示在上面tab中的省份

private StringdefaultCity ="城市"; //显示在上面tab中的城市

private StringdefaultDistrict ="区县"; //显示在上面tab中的区县

private ListmRvData; // 用来在recyclerview显示的数据

private AddressAdaptermAdapter;  // recyclerview 的adapter

private YwpAddressBeanmYwpAddressBean; // 总数据

private YwpAddressBean.AddressItemBeanmSelectProvice; //选中 省份bean

private YwpAddressBean.AddressItemBeanmSelectCity;//选中 城市bean

private YwpAddressBean.AddressItemBeanmSelectDistrict;//选中 区县bean

private int mSelectProvicePosition =0; //选中 省份 位置

private int mSelectCityPosition =0;//选中 城市  位置

private int mSelectDistrictPosition =0;//选中 区县  位置

private OnAddressPickerSureListenermOnAddressPickerSureListener;

public AddressPickerView(Context context) {

super(context);

    init(context);

}

public AddressPickerView(Context context, @Nullable AttributeSet attrs) {

super(context, attrs);

    init(context);

}

public AddressPickerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

    init(context);

}

/**

* 初始化

*/

private void init(Context context) {

mContext = context;

    mRvData =new ArrayList();

    // UI

    View rootView =inflate(mContext, R.layout.address_picker_view, this);

    // tablayout初始化

    mTabLayout = (TabLayout) rootView.findViewById(R.id.tlTabLayout);

    mTabLayout.addTab(mTabLayout.newTab().setText(defaultProvince));

    mTabLayout.addTab(mTabLayout.newTab().setText(defaultCity));

    mTabLayout.addTab(mTabLayout.newTab().setText(defaultDistrict));

    mTabLayout.addOnTabSelectedListener(tabSelectedListener);

    // recyclerview adapter的绑定

    mRvList = (RecyclerView) rootView.findViewById(R.id.rvList);

    mRvList.setLayoutManager(new LinearLayoutManager(context));

    mAdapter =new AddressAdapter();

    mRvList.setAdapter(mAdapter);

    // 初始化默认的本地数据  也提供了方法接收外面数据

    mRvList.post(new Runnable() {

@Override

        public void run() {

initData();

        }

});

}

/**

* 初始化数据

* 拿assets下的json文件

*/

private void initData() {

StringBuilder jsonSB =new StringBuilder();

    try {

BufferedReader addressJsonStream =new BufferedReader(new InputStreamReader(mContext.getAssets().open("address.json")));

        String line;

        while ((line = addressJsonStream.readLine()) !=null) {

jsonSB.append(line);

        }

}catch (IOException e) {

e.printStackTrace();

    }

// 将数据转换为对象

    mYwpAddressBean =new Gson().fromJson(jsonSB.toString(), YwpAddressBean.class);

    if (mYwpAddressBean !=null) {

mRvData.clear();

        mRvData.addAll(mYwpAddressBean.getProvince());

        mAdapter.notifyDataSetChanged();

    }

}

/**

* 开放给外部传入数据

* 暂时就用这个Bean模型,如果数据不一致就需要各自根据数据来生成这个bean了

*/

public void initData(YwpAddressBean bean) {

if (bean !=null) {

mSelectDistrict =null;

        mSelectCity =null;

        mSelectProvice =null;

        mTabLayout.getTabAt(0).select();

        mYwpAddressBean = bean;

        mRvData.clear();

        mRvData.addAll(mYwpAddressBean.getProvince());

        mAdapter.notifyDataSetChanged();

    }

}

//点确定

private void sure() {

if (mSelectProvice !=null

mSelectCity !=null

mSelectDistrict !=null) {

//  回调接口

        if (mOnAddressPickerSureListener !=null) {

mOnAddressPickerSureListener.onSureClick(mSelectProvice.getN(), mSelectCity.getN(), mSelectDistrict.getN());

        }

}else {

Toast.makeText(mContext, "地址还没有选完整哦", Toast.LENGTH_SHORT).show();

    }

}

@Override

protected void onDetachedFromWindow() {

super.onDetachedFromWindow();

  // mYwpAddressBean = null;

}

/**

* TabLayout 切换事件

*/

TabLayout.OnTabSelectedListenertabSelectedListener =new TabLayout.OnTabSelectedListener() {

@Override

    public void onTabSelected(TabLayout.Tab tab) {

mRvData.clear();

        switch (tab.getPosition()) {

case 0:

mRvData.addAll(mYwpAddressBean.getProvince());

                mAdapter.notifyDataSetChanged();

                // 滚动到这个位置

                mRvList.smoothScrollToPosition(mSelectProvicePosition);

break;

            case 1:

// 点到城市的时候要判断有没有选择省份

                if (mSelectProvice !=null) {

for (YwpAddressBean.AddressItemBean itemBean :mYwpAddressBean.getCity()) {

if (itemBean.getP().equals(mSelectProvice.getI()))

mRvData.add(itemBean);

                    }

}else {

Toast.makeText(mContext, "请您先选择省份", Toast.LENGTH_SHORT).show();

                }

mAdapter.notifyDataSetChanged();

                // 滚动到这个位置

                mRvList.smoothScrollToPosition(mSelectCityPosition);

break;

            case 2:

// 点到区的时候要判断有没有选择省份与城市

                if (mSelectProvice !=null mSelectCity !=null) {

for (YwpAddressBean.AddressItemBean itemBean :mYwpAddressBean.getDistrict()) {

if (itemBean.getP().equals(mSelectCity.getI()))

mRvData.add(itemBean);

                    }

}else {

Toast.makeText(mContext, "请您先选择省份与城市", Toast.LENGTH_SHORT).show();

                }

mAdapter.notifyDataSetChanged();

                // 滚动到这个位置

                mRvList.smoothScrollToPosition(mSelectDistrictPosition);

break;

        }

}

@Override

    public void onTabUnselected(TabLayout.Tab tab) {

}

@Override

    public void onTabReselected(TabLayout.Tab tab) {

}

};

/**

* 下面显示数据的adapter

*/

class AddressAdapterextends RecyclerView.Adapter {

@Override

    public ViewHolderonCreateViewHolder(ViewGroup parent, int viewType) {

return new ViewHolder(LayoutInflater.from(mContext).inflate(R.layout.item_address_text, parent, false));

    }

@Override

    public void onBindViewHolder(final ViewHolder holder, final int position) {

final int tabSelectPosition =mTabLayout.getSelectedTabPosition();

        holder.mTitle.setText(mRvData.get(position).getN());

        holder.mTitle.setTextColor(defaultUnSelectedColor);

        // 设置选中效果的颜色

        switch (tabSelectPosition) {

case 0:

if (mRvData.get(position) !=null

mSelectProvice !=null

mRvData.get(position).getI().equals(mSelectProvice.getI())) {

holder.mTitle.setTextColor(defaultSelectedColor);

                }

break;

            case 1:

if (mRvData.get(position) !=null

mSelectCity !=null

mRvData.get(position).getI().equals(mSelectCity.getI())) {

holder.mTitle.setTextColor(defaultSelectedColor);

                }

break;

            case 2:

if (mRvData.get(position) !=null

mSelectDistrict !=null

mRvData.get(position).getI().equals(mSelectDistrict.getI())) {

holder.mTitle.setTextColor(defaultSelectedColor);

                }

break;

        }

// 设置点击之后的事件

        holder.mTitle.setOnClickListener(new OnClickListener() {

@Override

            public void onClick(View v) {

// 点击 分类别

                switch (tabSelectPosition) {

case 0:

mSelectProvice =mRvData.get(position);

                        // 清空后面两个的数据

                        mSelectCity =null;

                        mSelectDistrict =null;

                        mSelectCityPosition =0;

                        mSelectDistrictPosition =0;

                        mTabLayout.getTabAt(1).setText(defaultCity);

                        mTabLayout.getTabAt(2).setText(defaultDistrict);

                        // 设置这个对应的标题

                        mTabLayout.getTabAt(0).setText(mSelectProvice.getN());

                        // 跳到下一个选择

                        mTabLayout.getTabAt(1).select();

                        mSelectProvicePosition =position;

break;

                    case 1:

mSelectCity =mRvData.get(position);

                        // 清空后面一个的数据

                        mSelectDistrict =null;

                        mSelectDistrictPosition =0;

                        mTabLayout.getTabAt(2).setText(defaultDistrict);

                        // 设置这个对应的标题

                        mTabLayout.getTabAt(1).setText(mSelectCity.getN());

                        // 跳到下一个选择

                        mTabLayout.getTabAt(2).select();

                        mSelectCityPosition =position;

break;

                    case 2:

mSelectDistrict =mRvData.get(position);

                        // 没了,选完了,这个时候可以点确定了

                        mTabLayout.getTabAt(2).setText(mSelectDistrict.getN());

                        notifyDataSetChanged();

                        mSelectDistrictPosition =position;

                        sure();

break;

                }

}

});

    }

@Override

    public int getItemCount() {

return mRvData.size();

    }

class ViewHolderextends RecyclerView.ViewHolder {

TextViewmTitle;

        ViewHolder(View itemView) {

super(itemView);

            mTitle = (TextView) itemView.findViewById(R.id.itemTvTitle);

        }

}

}

/**

* 点确定回调这个接口

*/

public interface OnAddressPickerSureListener {

void onSureClick(String proviceName,String cityName,String earaName);

}

public void setOnAddressPickerSure(OnAddressPickerSureListener listener) {

this.mOnAddressPickerSureListener = listener;

}

Android 仿微博,探索使用ShortcutManager添加应用程序的快捷方式

在Android 7.1(API 25)之后添加的新功能,应用快捷方式。ShortcutManager管理一个应用程序的快捷方式。只要在长按应用图标的情况下,在应用图标上显示的快捷方式,用户可以快速访问任意一个Activity。

现在市场上已经是有很多应用增加了这项功能,例如微博、美团、支付宝、知乎、印象笔记等。

按照惯例,我们先看看效果图:

二、这个Dome主要是通过动态的方式,下面我们来看看动态创建的方式,是通过ShortcutManager实现快捷方式的增加、删除、更新的操作,使用起来很简单。

strings.xml

在进来的页面中,我们通过传值去做一些业务逻辑判断

好了,本篇文章就这样啦,存在总结不到位的地方还望指导,感谢~

最后附上官网地址:

Android仿微信全局字体大小调整

最近项目添加了一项调整应用字体大小功能,做完后空闲之余总结一下。本功能仿照微信应用“设置” - “通用” - “字体大小”功能,又有一点区别。据我所知,常见改变全局字体大小方法有两种,我把这两种分为可控和不可控,为什么这么分呢,当然不是为了方便记忆。那么简单说下两者方式的实现过程:

1、不可控:通过重写Actiivity的getResources()方法更新应用的字体倍数来调整全局字体大小

2、可控:通过setTheme()方法,一开始就初始化设置不同风格的字体样式来更改全局字体大小。

而本文正式采用了第一种方案,主要是中途添加该功能,时间也不充裕,抽取字体大小又太过耗时。

微信字体大小个人猜测使用第二种方案,后者是更好的实现方式也不一定。

xml使用方式:

2、滑动按钮改变当前页面预览字体大小

3、返回时,保存放大倍数并重启应用

4、初始化应用时配置字体放大倍数。

源码地址:

到这里就结束啦。

【Android自定义View】仿Photoshop取色器ColorPicker(一)

一款仿Photoshop取色器的Android版取色器。采用HSV颜色空间,可手动选取想要的颜色,也可以手动输入具体颜色的16进制编码以获取颜色(如:0xFFFFFF表示白色)。

github地址:

ColorPicker效果图

ColorPicker 项目结构如下图所示:

核心自定义控件: ColorPickerView.java

颜色拾取对话框: ColorPickerDialog.java

颜色转换相关工具: Utils.java

对话框布局文件: dialog_color_picker.xml(纵向布局) + dialog_color_picker.xml(横向布局)

其他文件内容都为项目构建时的默认内容。

在开始了解 ColorPicker 的具体实现之前,需要首先了解一些颜色相关的概念。

而 ColorPicker库 的 核心自定义控件ColorPickerView 的颜色拾取功能就是基于 HSV颜色空间 的。而且HSV和RGB是可以进行转换。不过不必担心转换,因为android.graphics.Color.java提供了转换方法:

下一篇主要讲解ColorPickerView的绘制流程: 仿Photoshop取色器ColorPicker(二)


新闻名称:android仿,android仿微信聊天界面
标题路径:http://cdkjz.cn/article/hoeosd.html
多年建站经验

多一份参考,总有益处

联系快上网,免费获得专属《策划方案》及报价

咨询相关问题或预约面谈,可以通过以下方式与我们联系

业务热线:400-028-6601 / 大客户专线   成都:13518219792   座机:028-86922220