Android自定义控件案例汇总1(菜单、popupwindow、viewpager)

自定义控件是根据自己的需要自己来编写控件。安卓自带的控件有时候无法满足你的需求,这种时候,我们只能去自己去实现适合项目的控件。同时,安卓也允许你去继承已经存在的控件或者实现你自己的控件以便优化界面和创造更加丰富的用户体验。在平常的项目中,我们 人为的把自定义控件分为两种:一种是组合方式实现。一种是通过继承view或viewgroup及其子类实现。两者都可以实现我们想要的效果,因此,我们可以根据自己的需求,选择合适的方案。本文以案例的形式来显示几种较为常见的自定义控件。

案例一 优酷菜单:

功能介绍: 手机界面的底部中央有一个半圆,初始状态显示三级菜单,由外到内分别是第三级菜单,第二级菜单,第三级菜单。每个菜单中有一些按钮,可以用3个容器(RelativeLayout)来表示3个菜单,往里面添加按钮即可。当再次点击中心位置的图片式,隐藏外面两层的的条目。再次点击重心位置的图片时,旋转出二级菜单。点击二级菜单中心位置时,旋转出三级菜单,再次点击则隐藏三级菜单。以上就是优酷菜单要实现的功能。

实现步骤:

1. 完成布局文件。由于控件较多所以优酷菜单的布局较为复杂,但是可以在一个根布局设置三个子线性布局来包裹每一个小的控件。通过调整margin值来是使得界面更加的美观。注意3个菜单布局的顺序,先放men3,然后menu2,然后menu1,顺序不能反,因为越往后放的菜单越在界面的上方,这样面积最小的菜单1会在最上方,菜单1不会遮挡到下面的菜单2和菜单3。

2. 完成布局文件后,创建一个类,在该类中实现业务逻辑。首先要创建两个布尔类型的常量存储菜单的状态。通过swich语句判断被点击的控件是二级菜单还是一级菜单。如果是一级菜单的中心被点击,则判断三级菜单是否打开。如果三级菜单打开着,则隐藏一级菜单和二级菜单,并修改状态。如果三级菜单隐藏着则判断二级菜单是否隐藏。如果二级菜单打开着,则隐藏二级菜单。如果二级菜单隐藏则打开二级菜单。如果是二级菜单的中心被点击,则只需要判断三级菜单是否隐藏。如果三级菜单打开着,则隐藏三级菜单。如果三级菜单隐藏则打开三级菜单。同时还要修改菜单的状态。

3. 接下来可以在一个工具类中实现动画的效果。步骤2中的隐藏和显示均都是通过动画效果实现的。这里的动画效果用到的是补间动画,为RotateAnimation对象传入起始角度,结束的角度,参考对象和参考点坐标。一个小细节是将setFillAfter属性设为true,表示从结束位置开始动画,避免动画结束后又回到起始位置。隐藏和显示区别是旋转的起始角度和结束角度,这里显示设定的起始角度是-180,结束角度为0。隐藏设定的起始角度为0,结束角度为-180。当然也可以设定为其他值,取决于自己想要的效果。

4. 代码优化。快速点击按钮时会发现菜单还没隐藏完就开始显示了,或者还没显示完又隐藏了。解决方案:监听动画的开启次数来判断是否需要执行画,给动画类添加一个监听器。设置一个成员变量。当开始开始动画是执行加一操作,结束动画是执行减一操作。这样只有当常量为零时,才没有动画。因此swich语句中加入判断如果当前存在动画,等待动画执行完之后在进入下面的逻辑。

菜单选择界面的布局:

<?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">

  <RelativeLayout
    android:id="@+id/rl_menu3"
    android:layout_width="280dp"
    android:layout_height="140dp"
    android:layout_alignParentBottom="true"
    android:layout_centerHorizontal="true"
    android:background="@drawable/level3">

    <ImageButton
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_alignParentBottom="true"
      android:layout_marginBottom="6dp"
      android:layout_marginLeft="12dp"
      android:background="@drawable/channel1" />

    <ImageButton
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_alignParentBottom="true"
      android:layout_marginBottom="46dp"
      android:layout_marginLeft="32dp"
      android:background="@drawable/channel2" />

    <ImageButton
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_alignParentBottom="true"
      android:layout_marginBottom="80dp"
      android:layout_marginLeft="60dp"
      android:background="@drawable/channel3" />

    <ImageButton
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_centerHorizontal="true"
      android:layout_marginTop="6dp"
      android:background="@drawable/channel4" />

    <ImageButton
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_alignParentBottom="true"
      android:layout_alignParentRight="true"
      android:layout_marginBottom="80dp"
      android:layout_marginRight="60dp"
      android:background="@drawable/channel5" />

    <ImageButton
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_alignParentBottom="true"
      android:layout_alignParentRight="true"
      android:layout_marginBottom="46dp"
      android:layout_marginRight="32dp"
      android:background="@drawable/channel6" />

    <ImageButton
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_alignParentBottom="true"
      android:layout_alignParentRight="true"
      android:layout_marginBottom="6dp"
      android:layout_marginRight="12dp"
      android:background="@drawable/channel7" />

  </RelativeLayout>

  <RelativeLayout
    android:id="@+id/rl_menu2"
    android:layout_width="180dp"
    android:layout_height="90dp"
    android:layout_alignParentBottom="true"
    android:layout_centerHorizontal="true"
    android:background="@drawable/level2">

    <ImageButton
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_alignParentBottom="true"
      android:layout_marginBottom="6dp"
      android:layout_marginLeft="12dp"
      android:background="@drawable/icon_search" />

    <ImageButton
      android:id="@+id/btn_menu2"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_centerHorizontal="true"
      android:layout_marginTop="4dp"
      android:background="@drawable/icon_menu" />

    <ImageButton
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_alignParentBottom="true"
      android:layout_alignParentRight="true"
      android:layout_marginBottom="6dp"
      android:layout_marginRight="12dp"
      android:background="@drawable/icon_myyouku" />

  </RelativeLayout>

  <RelativeLayout
    android:id="@+id/rl_menu1"
    android:layout_width="100dp"
    android:layout_height="50dp"
    android:layout_alignParentBottom="true"
    android:layout_centerHorizontal="true"
    android:background="@drawable/level1">

    <ImageButton
      android:id="@+id/btn_menu1"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_centerInParent="true"
      android:background="@drawable/icon_home" />

  </RelativeLayout>
</RelativeLayout>

主界面的布局,在代码中用打气筒把菜单布局打到主界面上。

<?xml version="1.0" encoding="utf-8"?>
<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"
  android:gravity="center"
  tools:context="com.example.selectbar.Selectbar">

  <com.example.selectbar.Rotate
    android:layout_centerInParent="true"
    android:id="@+id/rotate"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

</RelativeLayout>

主程序是空实现。

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

public class Selectbar extends AppCompatActivity {

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

主要逻辑的实现。

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.RelativeLayout;

import com.example.selectbar.com.example.selectbar.utils.utils;

/**
 * Created by huang on 2016/11/22.
 */
public class Rotate extends RelativeLayout implements View.OnClickListener {
  private static final String TAG = "Rotate";
  private RelativeLayout rl_menu1, rl_menu2, rl_menu3;
  private boolean menu2showing = true;
  private boolean menu3showing = true;

  public Rotate(Context context) {
    super(context,null);
  }

  public Rotate(Context context, AttributeSet attrs) {
    super(context, attrs);
    initdata(context);
  }

  private void initdata(Context context) {
    Log.i(TAG, "initdata: text");
    View view = View.inflate(context,R.layout.activity_rolate,null);
    view.findViewById(R.id.btn_menu1).setOnClickListener(this);
    view.findViewById(R.id.btn_menu2).setOnClickListener(this);
    rl_menu1 = (RelativeLayout) view.findViewById(R.id.rl_menu1);
    rl_menu2 = (RelativeLayout) view.findViewById(R.id.rl_menu2);
    rl_menu3 = (RelativeLayout) view.findViewById(R.id.rl_menu3);
    addView(view);
  }
  @Override
  public void onClick(View v) {
    switch (v.getId()) {
      case R.id.btn_menu2:
        if (utils.hasAnimationexcuting()) {
          return;
        }
        if (menu3showing) {
          utils.hiden(rl_menu3);
        } else {
          utils.show(rl_menu3);
        }
        menu3showing = !menu3showing;
        break;

      case R.id.btn_menu1:
        if (utils.hasAnimationexcuting()) {
          return;
        }
        if (menu3showing) {
          utils.hiden(rl_menu3);
          menu3showing = false;
          utils.hiden(rl_menu2, 300);

        } else if (menu2showing) {
          utils.hiden(rl_menu2);
        } else {
          utils.show(rl_menu2);
        }
        menu2showing = !menu2showing;
        break;
    }
  }
}

还需要一个工具类实现动画的效果。

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

/**
 * Created by huang on 2016/11/22.
 */
public class utils {
  private static final String TAG = "utils";
  private static void setviewclickable(View view, boolean clickable) {
    view.setClickable(clickable);
    if (view instanceof ViewGroup) {
      ViewGroup viewgroup = (ViewGroup) view;
      for (int i = 0; i < viewgroup.getChildCount(); i++) {
        View child = ((ViewGroup) view).getChildAt(i);
        child.setClickable(clickable);
      }
    }
  }

  public static void hiden(View view) {
    float fromDegreeas = 0;
    float toDegrees = -180f;
    rotateview(view, fromDegreeas, toDegrees, 0l);
    setviewclickable(view, false);
  }

  public static void hiden(View view, long startoffset) {
    float fromDegreeas = 0;
    float toDegrees = -180f;
    rotateview(view, fromDegreeas, toDegrees, startoffset);
    setviewclickable(view, false);
  }

  public static void show(View view) {
    float fromDegrees = -180f;
    float toDegrees = 0;
    rotateview(view, fromDegrees, toDegrees, 0l);
    setviewclickable(view, true);
  }

  public static boolean hasAnimationexcuting() {
    return startcount > 0;
  }

  public static void rotateview(View view, float fromDegrees, float toDegrees, long startoffset) {
    int pivotXType = RotateAnimation.RELATIVE_TO_SELF;
    int pivotYType = RotateAnimation.RELATIVE_TO_SELF;
    float pivotXValue = 0.5f;
    float pivatYValue = 1.0f;
    RotateAnimation ra = new RotateAnimation(fromDegrees, toDegrees, pivotXType, pivotXValue, pivotYType, pivatYValue);
    ra.setDuration(500);
    ra.setFillAfter(true);
    ra.setStartOffset(startoffset);
    ra.setAnimationListener(listener);
    view.startAnimation(ra);
  }

  public static int startcount;
  static Animation.AnimationListener listener = new Animation.AnimationListener() {
    @Override
    public void onAnimationStart(Animation animation) {
      startcount++;
//      Log.i(TAG, "onAnimationStart: " +startcount);
    }

    @Override
    public void onAnimationEnd(Animation animation) {
      startcount--;
//      Log.i(TAG, "onAnimationEnd: " + startcount);
    }

    @Override
    public void onAnimationRepeat(Animation animation) {

    }
  };
}

案例二   popupwindow实现下拉列表:

功能介绍:创建一个textview,当我们点击textview时会弹出一个列表,列表中存放的是数字信息和一张删除图片。列表是用listview实现。点击删除图片可以将本条记录从列表中删除。本案例的有两种,一种是通过动画的缩放实现弹出效果,另一种是采取popupwindow。本文采用的是第二种方案。

实现步骤:

添加布局文件。首先要在界面上放置一个textview,在textview的右边放置一个下拉图片。为了更方便地摆放控件,可以采用相对布局,这样只要保证imageview和textview上对齐、下对齐、右对齐就可以实现要现实的效果。为了是界面更美观,可以把图片设为透明的,即背景为null。这里将popupwindow弹出来的界面用listview表示。因此还要写一个单独的listview以及每一个条目的布局,然后用打气筒打到textview的下方、
Pupupwindow的编写。Popupwindow的编写有两个关键的步骤,一个是new一个pupupwimdow对象,将要显示的布局、布局的高和宽、是否可聚等相关的参数传入。这里pupupwindow的显示界面是用的打气筒把listview加载进来。同时listview条目的布局也用到inflate。因此用到两次打气筒。同时为每一个listview的条目设置条目点击的监听事件,这样在条目被点击时候可以将条目的内容显示在textview中。。Popupwindow的编写另一个关键性的步骤是showAsDropDown,即将要显示在哪个控件下方,偏移量多少出传进来。需要注意的是控件的实际宽高和看到的宽高有一定的误差,只是因为控件的背景用一定的宽度。还有一点就是,按返回键时PopupWindow没法隐藏,给PopupWindow设置一个背景即可解决这个问题,如下:popupWindow.setBackgroundDrawable(new ColorDrawable())。每次显示PopupWindow时都创建一个新的PopupWindow对象,其实可以复用一个PopupWindow对象的。即每次创建前先判断popupwindow是否为空。
Listiview条目的编写较为定。这里做了两处的优化。一个是服用conterview,开始操作之前判断conterview是否为空。若为空创建一个新的view,否则复用被回收的conterview。另一处的优化是,每一次finviewbyid会消耗大量的内存。因此可以单独定义一个类,存放控件,在cnterview为空时创建一次。每次调用时只需要调用定义类中的控件。还有一点是,要是条目上的删除图标有用还要对删除图片设定一个点击事件。一个小细节是,当listvie条目中存在button及其子类时,会抢占焦点。因此这里删除图片的标签用的是imageview。当然你也可以采取其他方式,比如,在条目的根布局加上这个属性:android:descendantFocusability="blocksDescendants"。

主界面的布局:

<?xml version="1.0" encoding="utf-8"?>
<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"
  android:layout_margin="17dp"
  android:paddingBottom="@dimen/activity_vertical_margin"
  android:paddingLeft="@dimen/activity_horizontal_margin"
  android:paddingRight="@dimen/activity_horizontal_margin"
  android:paddingTop="@dimen/activity_vertical_margin"
  tools:context="com.example.popuwindow.MainActivity">

  <RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <EditText
      android:id="@+id/et_number"
      android:layout_width="200dp"
      android:layout_height="wrap_content"
      android:hint="输入账号" />

    <ImageButton
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_alignBottom="@id/et_number"
      android:layout_alignRight="@id/et_number"
      android:layout_alignTop="@id/et_number"
      android:background="@null"
      android:onClick="showNumberListToggle"
      android:src="@mipmap/down_arrow" />
  </RelativeLayout>
</RelativeLayout>

listview条目的布局

<?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="wrap_content"
  android:gravity="center_vertical"
  android:orientation="horizontal"
  android:padding="6dp">

  <ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@mipmap/user" />

  <TextView
    android:id="@+id/tv_numer"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_marginLeft="6dp"
    android:layout_weight="1"
    android:text="10000"
    android:textSize="18sp" />

  <ImageView
    android:id="@+id/ib_del"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@null"
    android:src="@mipmap/delete" />
</LinearLayout>

单独写一个listview。

<?xml version="1.0" encoding="utf-8"?>
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:cacheColorHint="@null"
  android:background="@mipmap/listview_background"
  android:descendantFocusability="blocksDescendants">
</ListView>

主程序中的逻辑。

import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.PopupWindow;

public class MainActivity extends AppCompatActivity {
  private EditText et_number;
  private PopupWindow popupwindow;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    et_number = (EditText) findViewById(R.id.et_number);
  }

  public void showNumberListToggle(View view) {
    if (popupwindow == null) {          //复用popupwindow
      View contentView = createContent();
      int width = et_number.getWidth() - 4;
      int height = 400;
      boolean focusable = true;
      popupwindow = new PopupWindow(contentView, width, height, focusable);
      popupwindow.setBackgroundDrawable(new ColorDrawable());
    }
    View anchor = et_number;
    int xoff = 2;
    int yoff = -5;
    popupwindow.showAsDropDown(anchor, xoff, yoff);
  }

  private View createContent() {
      ListView lv = (ListView) View.inflate(this, R.layout.activity_list, null);
      lv.setAdapter(new NumberListAdapter());
      lv.setVerticalScrollBarEnabled(false);
      lv.setOnItemClickListener(monitemclickListener);
    return lv;
  }

  AdapterView.OnItemClickListener monitemclickListener = new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
      String number = (String) parent.getItemAtPosition(position);
      et_number.setText(number);
      popupwindow.dismiss();
    }
  };
}

适配器的编写

import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.ArrayList;

/**
 * Created by huang on 2016/11/22.
 */
public class NumberListAdapter extends BaseAdapter {
  private ArrayList<String> numbers = new ArrayList();

  {
    for (int i = 0; i < 30; i++) {
      numbers.add(10000 + i + "" );
    }
  }

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

  @Override
  public Object getItem(int position) {
    return numbers.get(position);
  }

  @Override
  public long getItemId(int position) {
    return position;
  }

  @Override
  public View getView(final int position, View convertView, ViewGroup parent) {
    View view;
    viewHolder holder;
    if(convertView == null){
      view = View.inflate(parent.getContext(),R.layout.item_number_list,null);
      holder = new viewHolder();
      holder.ib_del = (ImageView) view.findViewById(R.id.ib_del);
      holder.tv_number = (TextView) view.findViewById(R.id.tv_numer);
      view.setTag(holder);
    }else{
      view = convertView;
      holder = (viewHolder)view.getTag();
    }
    holder.ib_del.setImageResource(R.mipmap.delete);
    holder.tv_number.setText(numbers.get(position));
    holder.ib_del.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        numbers.remove(position);
        notifyDataSetChanged();
      }
    });
    return view;
  }

  static class viewHolder{
     TextView tv_number;
     ImageView ib_del;
  }
}

案例三 viewpager实现轮播图: 

功能介绍:  广告条的实现,又被称为轮播图。在手机界面的最上方放置一个ViewPager功能,实现界面的左右滑动。滑动又分为两种,一种是间隔一定的时间自动滑动,同时还支持手势的左右滑动。一个小细节是在轮播图底部放置和图片数量相等的小点,用于表示当前哪个图片被选中。
实现步骤:

1. 布局文件有两部分组成,一个是viewpager,一个是底部的条和小圆点。Viewpager存在于v4包下,因此可兼容到Android1.6。底部的条和小圆点放在一个线性布局中,让放在viewpager的底部,同时文字和圆点为中心位置。这里特别说一下小圆点的实现。小圆点使用shape图做出来的。由于无法再布局文件中获取圆点的个数,因此可以在布局文件中放置一个LinearLayout,然后在java代码中将view对象向该LinearLayout中添加。同时将白点和黑点的状态选择器设置为view的背景。
2. 接下来是viewpager的编写。编写viewpager的关键是写适配器。写一个类继承PagerAdapter,重写其中的方法。Viewpager默认是加载三张图片,屏幕中间一张,屏幕左边和屏幕右边各一张。我们希望轮播图能够循环的播放,因此可以给getcount返回一个足够大的值,初始化轮播图时,将轮播图的初始位置设置在中间,这样就可以实现循环播放。当我们把getcount返回值设为一个很大的值时,在instantiateItem中也要对position进行判断。传入的的position是一个极大的值,但是图片的数量确实有限的,因此可以对position取余,这样就可以把position的位置和图片的数量对应起来。
3. 实现自动播放需要用到消息机制,间隔三秒调用显示下一张图片的方法。显示下一张图片是调用viewpager的setCurrentItem,传入下一个图片的item数。手指滑动时viewpager自身就有的功能,因此不需要再定义。
4. 最后要实现的功能是,viewpager底部的文字和小圆点跟随图片变化。这时候可以设定一个viewpager的监听事件,当图片发生改变时改变textview的值。然后遍历linearlayout的子view(子view中存发的是小圆点),当圆点的序列号和图片的序列号一直是,则选中圆点。当然,这里同样要对position取余,将position转化到于图片大小一致的范围。

主界面的实现:

<?xml version="1.0" encoding="utf-8"?>
<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"
  android:paddingBottom="@dimen/activity_vertical_margin"
  android:paddingLeft="@dimen/activity_horizontal_margin"
  android:paddingRight="@dimen/activity_horizontal_margin"
  android:paddingTop="@dimen/activity_vertical_margin"
  tools:context="com.example.advertisement.MainActivity">

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

  <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignBottom="@id/view_pager"
    android:background="@color/trans_balck"
    android:gravity="center"
    android:orientation="vertical"
    android:padding="5dp">

    <TextView
      android:id="@+id/tv_desc"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="图片描述"
      android:textColor="@android:color/white" />

    <LinearLayout
      android:id="@+id/ll_dots"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:orientation="horizontal"></LinearLayout>
  </LinearLayout>
</RelativeLayout>

状态选择器

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:state_selected="true" android:drawable="@drawable/shape_dot_select"/>
  <item android:drawable="@drawable/shape_dot_normal"/>
</selector>

shape图的绘制

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

<节省空间, 两个写下一起>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
 android:shape="oval">
   <solid android:color="@android:color/white"/>
</shape>

主程序中的业务逻辑

import android.os.Bundle;
import android.os.Handler;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
  private static final String TAG = "MainActivity";
  private int[] imageResids = {R.drawable.a, R.drawable.b, R.drawable.c, R.drawable.d, R.drawable.e};
  private String[] desc = {
      "巩俐不低俗,我就不能低俗",
      "扑树又回来啦!再唱经典老歌引万人大合唱",
      "揭秘北京电影如何升级",
      "乐视网TV版大派送",
      "热血屌丝的反杀"
  };

  private LinearLayout ll_dots;
  private TextView tv_desc;
  private ViewPager viewpager;
  private static final int SHOW_NEXT_PAGE = 0;

  private Handler handler = new Handler() ;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ll_dots = (LinearLayout) findViewById(R.id.ll_dots);
    tv_desc = (TextView) findViewById(R.id.tv_desc);
    viewpager = (ViewPager) findViewById(R.id.view_pager);
    viewpager.setAdapter(new BannerAapter(imageResids));
    viewpager.setOnPageChangeListener(listener);
    initDot();
    changeDotandDesc(0);
    viewpager.setCurrentItem(viewpager.getAdapter().getCount() / 2);
    handler.postDelayed(mRunnable,3000);
  }

  Runnable mRunnable = new Runnable() {
    @Override
    public void run() {
      shownextpage();
    }
  };
  /**初始化小圆点*/
  private void initDot() {
    for (int i = 0; i < imageResids.length; i++) {
      int _5dp = dp2px(5);
      LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(_5dp, _5dp);
      params.leftMargin = _5dp;
      View dot = new View(this);
      dot.setLayoutParams(params);
      dot.setBackgroundResource(R.drawable.select_dot);
      ll_dots.addView(dot);
    }
  }
  /**将pd数据转化为px数据*/
  private int dp2px(int pd) {
    float desity = getResources().getDisplayMetrics().density;
    return (int) (pd * desity + 0.5f);
  }

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

    }

    @Override
    public void onPageSelected(int position) {
      changeDotandDesc(position);
    }

    @Override
    public void onPageScrollStateChanged(int state) {

    }
  };

  public void changeDotandDesc(int position) {
    position = position % ll_dots.getChildCount();
    tv_desc.setText(desc[position]);
    for (int i = 0; i < ll_dots.getChildCount(); i++) {
      Log.i(TAG, "changeDotandDesc: " + i+ "  " + position);
      ll_dots.getChildAt(i).setSelected(i == position);
    }
  }

  private void shownextpage() {
    int currenItem = viewpager.getCurrentItem();
    viewpager.setCurrentItem(currenItem + 1);
    handler.postDelayed(mRunnable,3000);
  }
}

适配器的编写:

import android.support.v4.view.PagerAdapter;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;

/**
 * Created by huang on 2016/11/22.
 */
public class BannerAapter extends PagerAdapter {
  private int[] imageResIds;

  public BannerAapter(int[] imageResIds) {
    this.imageResIds = imageResIds;
  }

  @Override
  public int getCount() {
    return imageResIds.length * 10000 * 100;
  }

  @Override
  public boolean isViewFromObject(View view, Object object) {
    return view == object;
  }

  @Override
  public Object instantiateItem(ViewGroup container, int position) {
    ImageView imageview = new ImageView(container.getContext());
    position = position % imageResIds.length;
    imageview.setBackgroundResource(imageResIds[position]);
    container.addView(imageview);
    return imageview;
  }

  @Override
  public void destroyItem(ViewGroup container, int position, Object object) {
    container.removeView((ImageView) object);
  }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android自定义控件实现底部菜单(上)

    今天我们封装一个底部的菜单栏,这个大多数的应用都会用到,因此我们来自定义,方便以后项目的使用. 该控件的实现将分上下篇来介绍,先来看一个菜单栏的子控件–MenuItemM,这个控件有什么用呢?我们来看下一些主流app上的一些控件,如: 以上三张图片分别来自微信,今日头条和去哪儿,接下来我们将看到如何通过一个控件来实现不同的效果. 首先看下我写的一个deme 可以看到标题栏的消息控件,以及底部三个菜单项都是通过MenuItemM来实现的 这里面只是演示菜单栏的子控件,我们将在下一篇博客中完成底部菜

  • Android编程之下拉菜单Spinner控件用法示例

    本文实例讲述了Android下拉菜单Spinner控件用法.分享给大家供大家参考,具体如下: activity_main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent

  • Android自定义控件简单实现侧滑菜单效果

    侧滑菜单在很多应用中都会见到,最近QQ5.0侧滑还玩了点花样~~对于侧滑菜单,一般大家都会自定义ViewGroup,然后隐藏菜单栏,当手指滑动时,通过Scroller或者不断的改变leftMargin等实现:多少都有点复杂,完成以后还需要对滑动冲突等进行处理~~今天给大家带来一个简单的实现,史上最简单有点夸张,但是的确是我目前遇到过的最简单的一种实现~~~ 1.原理分析 既然是侧滑,无非就是在巴掌大的屏幕,塞入大概两巴掌大的布局,需要滑动可以出现另一个,既然这样,大家为啥不考虑使用Android

  • Android自定义控件实现底部菜单(下)

    在app中经常会用到底部菜单的控件,每次都需要写好多代码,今天我们用到了前几篇博客里的控件来进一步封装底部菜单.先看效果图: 主要包括以下功能: 1 设置icon以及点击之后的icon 2 设置文字 3 设置文字颜色以及点击之后的文字颜色 4 设置未读数量.更多以及new 我们先看如何使用,然后再看如何实现的 1 在布局文件中引用MenuM <com.landptf.view.MenuM android:id="@+id/mm_bottom" android:layout_wid

  • Android自定义控件之仿优酷菜单

    去年的优酷HD版有过这样一种菜单,如下图: 应用打开之后,先是三个弧形的三级菜单,点击实体键menu之后,这三个菜单依次旋转退出,再点击实体键menu之后,一级菜单会旋转进入,点击一级菜单,二级菜单旋转进入,点击二级菜单的menu键,三级菜单旋转进入,再次点击二级菜单的旋转键,三级菜单又会旋转退出,这时再点击一级菜单,二级菜单退出,最后点击实体menu键,一级菜单退出. 总体来说实现这样的功能: (1)点击实体menu键时,如果界面上有菜单显示,不管有几个,全部依次退出,如果界面上没有菜单显示,

  • Android使用自定义控件HorizontalScrollView打造史上最简单的侧滑菜单

    侧滑菜单在很多应用中都会见到,最近QQ5.0侧滑还玩了点花样~~对于侧滑菜单,一般大家都会自定义ViewGroup,然后隐藏菜单栏,当手指滑动时,通过Scroller或者不断的改变leftMargin等实现:多少都有点复杂,完成以后还需要对滑动冲突等进行处理~~今天给大家带来一个简单的实现,史上最简单有点夸张,但是的确是我目前遇到过的最简单的一种实现~~~ 1.原理分析 既然是侧滑,无非就是在巴掌大的屏幕,塞入大概两巴掌大的布局,需要滑动可以出现另一个,既然这样,大家为啥不考虑使用Android

  • Android控件View打造完美的自定义侧滑菜单

    一.概述 在App中,经常会出现侧滑菜单,侧滑滑出View等效果,虽然说Android有很多第三方开源库,但是实际上咱们可以自己也写一个自定义的侧滑View控件,其实不难,主要涉及到以下几个要点: 1.对Android中Window类中的DecorView有所了解 2.对Scroller类实现平滑移动效果 3.自定义ViewGroup的实现 首先来看看效果图吧:     下面现在就来说说这里咱们实现侧滑View的基本思路吧,这里我采用的是自定义一个继承于RelativeLayout的控件叫做XC

  • Android控件之菜单的创建方式

    显示效果图: 第一种创建方式 ------- package com.example.androidthismenus; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; public class MainActivity extends Activity { @Override protected void onCreate

  • Android 中 SwipeLayout一个展示条目底层菜单的侧滑控件源码解析

    由于项目上的需要侧滑条目展示收藏按钮,记得之前代码家有写过一个厉害的开源控件 AndroidSwipeLayout 本来准备直接拿来使用,但是看过 issue 发现现在有不少使用者反应有不少的 bug ,而且代码家现在貌似也不进行维护了.故自己实现了一个所要效果的一个控件.因为只是实现我需要的效果,所以大家也能看到,代码里有不少地方我是写死的.希望对大家有些帮助.而且暂时也不需要 AndroidSwipeLayout 大而全的功能,算是变相给自己做的项目精简代码了. 完整示例代码请看:GitHu

  • Android自定义控件案例汇总2(自定义开关、下拉刷新、侧滑菜单)

    案例四 自定义开关: 功能介绍:本案例实现的功能是创建一个自定义的开关,可以自行决定开关的背景.当滑动开关时,开关的滑块可跟随手指移动.当手指松开后,滑块根据开关的状态,滑到最右边或者滑到最左边,同时保存开关的状态,将开关的状态回调给调用者.当然,上述功能系统给定的switch控件也可以实现. 实现步骤: 1. 写一个类继承view,重写两个参数的构造方法.在构造方法中指定工作空间,通过attrs.getAttributeResourceValue方法将java代码中的属性值和xml中的属性值联

  • Android自定义控件案例汇总1(菜单、popupwindow、viewpager)

    自定义控件是根据自己的需要自己来编写控件.安卓自带的控件有时候无法满足你的需求,这种时候,我们只能去自己去实现适合项目的控件.同时,安卓也允许你去继承已经存在的控件或者实现你自己的控件以便优化界面和创造更加丰富的用户体验.在平常的项目中,我们 人为的把自定义控件分为两种:一种是组合方式实现.一种是通过继承view或viewgroup及其子类实现.两者都可以实现我们想要的效果,因此,我们可以根据自己的需求,选择合适的方案.本文以案例的形式来显示几种较为常见的自定义控件. 案例一 优酷菜单: 功能介

  • Android编程之ICS式下拉菜单PopupWindow实现方法详解(附源码下载)

    本文实例讲述了Android编程之ICS式下拉菜单PopupWindow实现方法.分享给大家供大家参考,具体如下: 运行效果截图如下: 右边这个就是下拉菜单啦,看见有的地方叫他 ICS式下拉菜单,哎哟,不错哦! 下面先讲一下实现原理: 这种菜单实际上就是一个弹出式的菜单,于是我们想到android PopupWindow 类,给他设置一个view 在弹出来不就OK了吗. PopupWindow 的用法也很简单 主要方法: 步骤1.new 一个实例出来,我们使用这个构造方法即可, 复制代码 代码如

  • Android仿微信长按菜单效果

    本文实例为大家分享了Android仿微信长按菜单展示的具体代码,供大家参考,具体内容如下 FloatMenu A menu style pop-up window that mimics WeChat.仿微信的长按菜单. 效果如下 引入方法: Github地址:https://github.com/JavaNoober/FloatMenu dependencies { .... compile 'com.noober.floatmenu:common:1.0.2' } 使用说明 使用方法1: A

  • Android自定义ViewGroup实现侧滑菜单

    目录 前言 一.常用的几种交互方式 1.1 事件的拦截处理 1.2 自行处理事件的几种方式 1.3 子View的滚动与协调交互 1.4 ViewGroup之间的嵌套与协调效果 二.ViewDragHelper的侧滑菜单实现 三.回调与封装 后记 前言 前文我们理解了ViewGroup的测量与布局,但是并没有涉及到多少的交互逻辑,而 ViewGroup 的交互逻辑说起来范围其实是比较大的.从哪开始说起呢? 我们暂且把 ViewGroup 的交互分为几块知识区, 事件的拦截. 事件的处理(内部又分不

  • Android仿美团下拉菜单(商品选购)实例代码

    美团电商应用平台大家使用非常频繁,下面小编通过本文给大家介绍电商应用平台中常用的选择类别下拉列表的实现.先给大家展示下效果图: 一.下拉列表的实现 其实实现方法有很多,这时实现的也没有什么技术含量,只是总结下自己在项目中的做法,也提供一个思路. 首先是列表的数据,一般数据都是从后台读过来,这里因为没有后台,所以写死在客户端: private void initMenuData() { menuData = new ArrayList<map<string, string=""

  • Android仿QQ空间底部菜单示例代码

    之前曾经在网上看到Android仿QQ空间底部菜单的Demo,发现这个Demo有很多Bug,布局用了很多神秘数字.于是研究了一下QQ空间底部菜单的实现,自己写了一个,供大家参考.效果如下图所示:   1.实现原理很简单,底部菜单是一个水平分布的LinearLayout,里面又是五个LinearLayout,它们的layout_weight都为1,意味着底部菜单的子控件将屏幕宽度平均分为5部分.五个LinearLayout除了中间那个,其余都在里面放置ImageView和TextView(中间先空

  • Android自定义控件eBook实现翻书效果实例详解

    本文实例讲述了Android自定义控件eBook实现翻书效果的方法.分享给大家供大家参考,具体如下: 效果图: Book.java文件: package com.book; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.ImageView; public class Book extend

  • Android 中Popwindow弹出菜单的两种方法实例

    Android 中Popwindow弹出菜单的两种方法实例 1.popWindow就是对话框的一种方式! 此文讲解的android中对话框的一种使用方式,它叫popWindow. 2.popWindow的特性 Android的对话框有两种:PopupWindow和AlertDialog.它们的不同点在于: AlertDialog的位置固定,而PopupWindow的位置可以随意. AlertDialog是非阻塞线程的,而PopupWindow是阻塞线程的. PopupWindow的位置按照有无偏

随机推荐