实例讲解Android应用中自定义组合控件的方法

自定义view大概可以分成:

  • 继承view
  • 组合view
  • 自己画的view(用paint和canvas)
  • 自定义viewgroup(widget)

最近又跟同学聊起来了,于是就准备自己实现一个imagebutton来练练手。(最简单的了)以及后面一个把imageview与textview结合使用的案例。

ImageButton
要实现ImageButton最容易想到的不就是把button和imageview合在一起么。嗯,人容易就想到这是一个组合自定义view。可是如何把一个image放到button上呢,自然就是用一个FrameLayout把button和imageview包裹起来,然后将这个layout当作一个weidgt。把一个layout当成一个控件我开始不太理解。后来了解到一些东西。

补充知识点(安卓的顶层视图)
在android里面,你的app界面的活动的视图并非是最顶级的视图。大家应该都知道viewtree。在安卓里面,最顶级的视图是一个叫DecorView的东西。它包括你的状态栏,标题栏,以及你的活动界面。而且这个活动界面,安卓会自动帮你提前弄进去一个FrameLayout。可以这么理解吧,在安卓这个上帝的面前,你的activity就是放在他的framelayout的一个个view。上一张图~

DecorView->LinearLayout(状态栏和activity)->FrameLayout(activity)->你自己的acitivty视图。

实例讲解
好啦,回归正题。我上代码了。
myimagebutton_layout.xml

<FrameLayout
 xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="match_parent">
 <Button
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:id="@+id/button_imagebutton"    />
 <ImageView
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:id="@+id/imageview_button"    />
</FrameLayout>

用一个framelayout把两个控件装起来,然后组合。组合了之后我们就去自定义我们这个控件的属性。button不用变对吧,用原生的就好了,就是需要有一个图片的src这个属性就好了。
在values目录下的attrs.xml文件_

<?xml version="1.0" encoding="utf-8"?>
<resources>在
  <declare-styleable name="MyImageButton">
    <attr name="Imagesrc" format="reference"/>
  </declare-styleable>
</resources>

一般来说,declare-styleable标签的名字都是你的自定义控件的名字。attr就是你的自定义控件属性。format是这个属性的值的数据类型。这里的reference表示引用。dimension表示的是dp或者sp的大小。还有一些可以自己去看看。定义好属性,我们就开始写控件了。
MyImageButton.java

public class MyImageButton2 extends FrameLayout{

  ImageView mImageView;
  Button mButton;
  int resId;

  public MyImageButton2(Context context) {
    super(context);
  }

  public MyImageButton2(Context context, AttributeSet attrs) {
    super(context, attrs);
    //导入布局
    LayoutInflater.from(context).inflate(R.layout.myimagebutton_layout, this);

   mImageView=(ImageView)findViewById(R.id.imageview_button);

   mButton = (Button) findViewById(R.id.button_imagebutton);
    //获得这个控件对应的属性。
   TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.MyImageButton);

    try{
     //获得属性值
      resId = a.getResourceId(R.styleable.MyImageButton_Imagesrc, 0);
    }finally {
     //回收这个对象
      a.recycle();
    }

    if(resId != 0){
      mImageView.setImageResource(resId);
    }
  }

  public void setImage(int resId){
    mImageView.setImageResource(resId);
  }

}

一般来说,继承view(就这么说吧,反正都是都是继承view的),实现两三个构造函数就可以了。在第二个里面有一个attr,这就是传进来的属性。如果resId不为默认值,就表示用户在xml里面传入了这个属性值,你也必须要写一个set方法,让用户可以在java代码中去改变属性值。
test.myimagebutton.layout.xml_

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="match_parent"
  android:layout_height="match_parent">

  <com.example.think.testview.customview.MyImageButton2
    xmlns:pt = "http://schemas.android.com/apk/res/com.example.think.testview"
    android:layout_height="100dp"
    android:layout_width="match_parent"
    pt:Imagesrc = "@drawable/ic_launcher"
    />

</LinearLayout>

效果图

另一个实例

这里我们来看一个view组合控件的例子:

<string-array name="bao_type">
   <item>测试1</item>
   <item>测试2</item>
   <item>测试3</item>
   <item>测试4</item>
 </string-array>
<?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:background="@color/gray_common_background"
  android:orientation="vertical"> 

  <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"> 

    <TextView
      android:id="@+id/txt_viewpage_bar1"
      style="@style/style_common_pagebar"
      android:textColor="@color/theme_red" /> 

    <TextView
      android:id="@+id/txt_viewpage_bar2"
      style="@style/style_common_pagebar" /> 

    <TextView
      android:id="@+id/txt_viewpage_bar3"
      style="@style/style_common_pagebar" /> 

    <TextView
      android:id="@+id/txt_viewpage_bar4"
      style="@style/style_common_pagebar" />
  </LinearLayout> 

  <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"> 

    <View
      android:id="@+id/view_viewpage_bar1"
      style="@style/style_common_pagebar_view" /> 

    <View
      android:id="@+id/view_viewpage_bar2"
      style="@style/style_common_pagebar_view" /> 

    <View
      android:id="@+id/view_viewpage_bar3"
      style="@style/style_common_pagebar_view" /> 

    <View
      android:id="@+id/view_viewpage_bar4"
      style="@style/style_common_pagebar_view" />
  </LinearLayout> 

  <android.support.v4.view.ViewPager
    android:id="@+id/common_viewpage_buttom"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_weight="1" />
</LinearLayout>
public interface SlbPageViewOnPageChangeListener {
   void onPageSelected(int position); 

   void onPageScrollStateChanged(int state);
 }
public class SlbPageViewBar extends LinearLayout { 

  private TextView[] mTotalTxtViews;
  private View[] mTotalViews;
  private List<TextView> mTxtViews;
  private List<View> mViews; 

  private ViewPager mViewPager;
  private SlbPageViewOnPageChangeListener mSlbPageViewOnPageChangeListener; 

  public SlbPageViewBar(Context context, AttributeSet attrs) {
    super(context, attrs);
    mTotalTxtViews = new TextView[4];
    mTotalViews = new View[4];
    mTxtViews = new ArrayList<>();
    mViews = new ArrayList<>();
    initView();
  } 

  private void initView() {
    View.inflate(getContext(), R.layout.layout_common_top_pageview_bar, this);
    mViewPager = (ViewPager) findViewById(R.id.common_viewpage_buttom);
    mTotalTxtViews[0] = (TextView) findViewById(R.id.txt_viewpage_bar1);
    mTotalTxtViews[1] = (TextView) findViewById(R.id.txt_viewpage_bar2);
    mTotalTxtViews[2] = (TextView) findViewById(R.id.txt_viewpage_bar3);
    mTotalTxtViews[3] = (TextView) findViewById(R.id.txt_viewpage_bar4);
    mTotalViews[0] = findViewById(R.id.view_viewpage_bar1);
    mTotalViews[1] = findViewById(R.id.view_viewpage_bar2);
    mTotalViews[2] = findViewById(R.id.view_viewpage_bar3);
    mTotalViews[3] = findViewById(R.id.view_viewpage_bar4); 

  } 

  /**
   * @param title 标题名称数组
   */ 

  public void setTitleView(String[] title) {
    int legth = title.length > 4 ? 4 : title.length;
    for (int i = 0; i < legth; i++) {
      mTotalTxtViews[i].setText(title[i]);
      mTotalTxtViews[i].setVisibility(View.VISIBLE);
      mTotalViews[i].setVisibility(View.INVISIBLE);
      mTotalTxtViews[i].setOnClickListener(new SlbTextViewOnLister(i));
      mTxtViews.add(mTotalTxtViews[i]);
      mViews.add(mTotalViews[i]);
    }
    mTotalViews[0].setVisibility(View.VISIBLE);
    mViewPager.setOnPageChangeListener(mOnButtomPageChangeListener);
  } 

  public ViewPager getViewPager(){
    return mViewPager;
  } 

  public void setSlbPageViewOnPageChangeListener(SlbPageViewOnPageChangeListener slbPageViewOnPageChangeListener) {
    this.mSlbPageViewOnPageChangeListener = slbPageViewOnPageChangeListener;
  } 

  private void changeViewBg(int textViewId, int viewId) {
    for (View view : mViews) {
      if (viewId == view.getId()) {
        view.setVisibility(View.VISIBLE);
      } else {
        view.setVisibility(View.INVISIBLE);
      }
    }
    for (TextView view : mTxtViews) {
      if (textViewId == view.getId()) {
        view.setTextColor(getResources().getColor(R.color.theme_red));
      } else {
        view.setTextColor(getResources().getColor(R.color.black_normal_text_33333));
      }
    }
  } 

  class SlbTextViewOnLister implements OnClickListener { 

    private int mItem; 

    public SlbTextViewOnLister(int item) {
      this.mItem = item; 

    } 

    @Override
    public void onClick(View v) {
      mViewPager.setCurrentItem(mItem);
    }
  } 

  private ViewPager.OnPageChangeListener mOnButtomPageChangeListener = new ViewPager.OnPageChangeListener() {
    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 

    } 

    @Override
    public void onPageSelected(int position) {
      switch (position) {
        case 0:
          changeViewBg(R.id.txt_viewpage_bar1, R.id.view_viewpage_bar1);
          break;
        case 1:
          changeViewBg(R.id.txt_viewpage_bar2, R.id.view_viewpage_bar2); 

          break;
        case 2:
          changeViewBg(R.id.txt_viewpage_bar3, R.id.view_viewpage_bar3);
          break;
        case 3:
          changeViewBg(R.id.txt_viewpage_bar4, R.id.view_viewpage_bar4);
          break;
      }
      if (mSlbPageViewOnPageChangeListener != null)
        mSlbPageViewOnPageChangeListener.onPageSelected(position);
    } 

    @Override
    public void onPageScrollStateChanged(int state) {
      if (mSlbPageViewOnPageChangeListener != null)
        mSlbPageViewOnPageChangeListener.onPageScrollStateChanged(state);
    }
  }; 

}
public class CommonViewpageAdapter extends FragmentPagerAdapter {
  private List<Fragment> mFragments;
  private String [] mTitles; 

  public CommonViewpageAdapter(FragmentManager fm, List<Fragment> fragments, String [] titles) {
    super(fm);
    mFragments = fragments;
    mTitles = titles;
  } 

  @Override
  public Fragment getItem(int position) {
    return mFragments.get(position);
  } 

  @Override
  public int getCount() {
    return mFragments.size();
  } 

  @Override
  public CharSequence getPageTitle(int position) {
    return mTitles[position];
  } 

  @Override
  public void destroyItem(ViewGroup container, int position, Object object) {
    super.destroyItem(container, position, object);
  }
}
<com.slfinance.app.slb.common.ui.view.SlbPageViewBar
    android:id="@+id/slbpv_buy_huoqibao_SlbPageViewBarshow"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"/>
private void initButtomPageFragment(SlbPageViewBar slbPageViewBar) {
  List<Fragment> fragmentList = new ArrayList<>();
  Test1Fragment test1Fragment = new Test1Fragment();
  Test2Fragment test2Fragment = new Test2Fragment();
  Test3Fragment test3Fragment = new Test3Fragment();
  Test4Fragment test4Fragment = new Test4Fragment();
  fragmentList.add(test1Fragment);
  fragmentList.add(test2Fragment);
  fragmentList.add(test3Fragment);
  fragmentList.add(test4Fragment);
  String[] titles = getResources().getStringArray(R.array.buy_huoqi_bao_zanquan_detail);
  slbPageViewBar.setTitleView(titles);
  CommonViewpageAdapter viewPagerAdapter = new CommonViewpageAdapter(
      getSupportFragmentManager(), fragmentList, titles);
  mButtomPageView.setAdapter(viewPagerAdapter);
  mButtomPageView.setOffscreenPageLimit(3);
  mButtomPageView.setCurrentItem(0);
}
(0)

相关推荐

  • Android中View自定义组合控件的基本编写方法

    有很多情况下,我们只要运用好Android给我提供好的控件,经过布局巧妙的结合在一起,就是一个新的控件,我称之为"自定义组合控件". 那么,这种自定义组合控件在什么情况下用呢?或者大家在做项目时候会发现,某些布局会被重复的利用,同一个布局的XML代码块会被重复的复制黏贴多次,这样会造成代码结构混乱不说,代码量也会增大,各种控件都需要在Java代码中被申明和处理相应的逻辑,工作量着实不小,所以,必须要找到一个合理的"偷懒"的方式,开动脑经去怎么简化以上说的不必要的麻烦

  • Android自定义控件之继承ViewGroup创建新容器

    欢迎大家来学习本节内容,前几节我们已经学习了其他几种自定义控件,分别是Andriod 自定义控件之音频条及 Andriod 自定义控件之创建可以复用的组合控件还没有学习的同学请先去学习下,因为本节将使用到上几节所讲述的内容. 在学习新内容之前,我们先来弄清楚两个问题: 1 . 什么是ViewGroup? ViewGroup是一种容器.它包含零个或以上的View及子View. 2 . ViewGroup有什么作用? ViewGroup内部可以用来存放多个View控件,并且根据自身的测量模式,来测量

  • Android组合控件实现功能强大的自定义控件

    通常情况下,Android实现自定义控件无非三种方式. Ⅰ.继承现有控件,对其控件的功能进行拓展. Ⅱ.将现有控件进行组合,实现功能更加强大控件. Ⅲ.重写View实现全新的控件 上文说过了如何继承现有控件来自定义控件:<Android继承现有控件拓展实现自定义控件textView>,这节我们来讨论第二个议题.怎么将控件组合来实现一个功能强大的自定义控件. 先看看创建组合控件的好处吧,创建组合控件能够很好的创建具有组合功能的控件集合.那我们一般又是怎么做的了,一般我们来继承一个合适的ViewG

  • Android自定义控件之组合控件学习笔记分享

    我们来讲一下自定义组合控件,相信大家也接触过自定义组合控件吧,话不多说,直接干(哈~哈~): 大家看到这个觉得这不是很简单的吗,这不就是写个布局文件就搞定嘛,没错,确实直接上布局就行,不过,我只是用这个简单的例子来讲一下自定义组合控件的用法. 首先看看,这一行行的条目看起来都长得差不多,只是图片和文字不一样,没错,就是看中这一点,我们可以把一个条目做成一个组合控件,做为一个整体,这样不管你有几个条目,就写几个组合控件就行了. 步骤: 1.先建立组合控件的布局 myView.xml <Relati

  • Android自定义控件之自定义组合控件(三)

    前言: 前两篇介绍了自定义控件的基础原理Android自定义控件基本原理详解(一).Android自定义控件之自定义属性(二).今天重点介绍一下如何通过自定义组合控件来提高布局的复用,降低开发成本,以及维护成本. 使用自定义组合控件的好处? 我们在项目开发中经常会遇见很多相似或者相同的布局,比如APP的标题栏,我们从三种方式实现标题栏来对比自定义组件带来的好处,毕竟好的东西还是以提高开发效率,降低开发成本为导向的.  1.)第一种方式:直接在每个xml布局中写相同的标题栏布局代码 <?xml v

  • Android自定义View之组合控件实现类似电商app顶部栏

    本文实例为大家分享了Android自定义View之组合控件,仿电商app顶部栏的相关代码,供大家参考,具体内容如下 效果图: 分析:左右两边可以是TextView和Button,设置drawableTop即可,中间的看着像是EditText,但是用过淘宝天猫等类似app的话会发现点击搜索不是在当前Activit进行搜索的,是跳转到另外的页面进行的,所以用TextView然后设置背景即可. 实现流程 参数列表: 设置属性文件:values下建立attrs.xml文件,添加需要自定义的属性. <?x

  • 在Android开发中使用自定义组合控件的例子

    一.定义一个XML布局文件 setting_item_view.xml <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height

  • Android自定义控件之创建可复用的组合控件

    前面已学习了一种自定义控件的实现,是Andriod 自定义控件之音频条,还没学习的同学可以学习下,学习了的同学也要去温习下,一定要自己完全的掌握了,再继续学习,贪多嚼不烂可不是好的学习方法,我们争取学习了一种技术就会一种技术,而且不光看了就算了,最好的方法就是看完我自己再练习下,再扩展下,在原来的基础上在添加一些东西,比如,增加一些功能实现等等. 今天我们打算学习下另外一种自定义控件,就是创建可重复使用的组合控件,那么问题来了: 什么是可重复使用? 就是在应用中,可以在多个地方共同使用一套代码.

  • Android自定义组合控件之自定义下拉刷新和左滑删除实例代码

    绪论 最近项目里面用到了下拉刷新和左滑删除,网上找了找并没有可以用的,有比较好的左滑删除,但是并没有和下拉刷新上拉加载结合到一起,要不就是一些比较水的结合,并不能在项目里面使用,小编一着急自己组合了一个,做完了和QQ的对比了一下,并没有太大区别,今天分享给大家,其实并不难,但是不知道为什么网上没有比较好的Demo,当你的项目真的很急的时候,又没有比较好的Demo,那么"那条友谊的小船儿真是说翻就翻啊",好了,下面先来具体看一下实现后的效果吧: 代码已经上传到Github上了,小伙伴们记

  • 探究Android中ListView复用导致布局错乱的解决方案

    首先来说一下具体的需求是什么样的: 需求如图所示,这里面有ABCD四个选项的题目,当点击A选项,如果A是正确的答案,则变成对勾的图案,如果是错误答案,则变成错误的图案,这里当时在写的时候觉得很简单,只要是在点击的时候判断我点击的选项与正确答案是否一样,是一样就将图片换成正确的样式,如果不一样就换成错误的样式,于是我便写了下面的代码(只贴出了核心Adapter中的代码) package com.fizzer.anbangproject_dahuo_test.Adapter; import andr

随机推荐