自定义view:图片显示指示器

      本篇文章使用Gallally控件和自定义view,实现一个带有图片指示器的图片集的展示效果。

      1.实现的效果

      显示一组可以滑动的图片,随着图片的切换,指示器小圆点也随着切换。

      2.自定义view的步骤

          (1)、自定义View的属性
          (2)、在View的构造方法中获得我们自定义的属性
          (3)、重写onMesure
          (4)、重写onDraw
          (3)不一定是必须的,当然了大部分情况下还是需要重写的。

           1、自定义View的属性,首先在res/values/ 下建立一个attrs.xml , 在里面定义我们的属性和声明我们的整个样式。

           

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="FlowIndicator">
        <attr name="count" format="integer" />
        <attr name="space" format="dimension" />
        <attr name="point_size" format="dimension" />
        <attr name="point_seleted_color" format="color|reference" />
        <attr name="point_normal_color" format="color|reference" />
        <attr name="point_radius" format="dimension" />
    </declare-styleable>

</resources>


我们定义了5个属性,format是值该属性的取值类型:
一共有:string,color,demension,integer,enum,reference,float,boolean,fraction,flag;

            在图片展示的布局中,我们声明Gallery控件以及自定义属性。布局文件head_view.xml内容如下:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res/com.dream.myqiyi"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <Gallery
        android:id="@+id/home_gallery"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:spacing="5dip" />

    <LinearLayout
        android:id="@+id/linearLayout1"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:background="#65000000"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/textView1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginBottom="5dip"
            android:layout_marginTop="5dip"
            android:text="承影之奇艺UIdemo"
            android:textColor="#ffffff"
            android:textSize="18dip" />

        <com.dream.myqiyi.widget.FlowIndicator
            android:id="@+id/myView"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="5dip"
            app:count="4"
            android:gravity="center"
            app:point_normal_color="#45000000"
            app:point_radius="3dip"
            app:point_seleted_color="#ffffff"
            app:point_size="5dip"
            app:space="10dip" />
    </LinearLayout>

</FrameLayout>


记住,一定要引入 xmlns:app="http://schemas.android.com/apk/res/com.dream.myqiyi" 命名空间,后面的包路径指的是项目的package。

             2, 自定义FlowIndicator类继承View类,在自定义的FlowIndicator类构造方法中,获得我们的自定义样式属性,并重写View类的onMeasure()和onView()方法。

public class FlowIndicator extends View {
	private int count;
	private float space, radius;
	private int point_normal_color, point_seleted_color;

	// 选中
	private int seleted = 0;

	// background seleted normal

	public FlowIndicator(Context context, AttributeSet attrs) {
		super(context, attrs);
		TypedArray a = context.obtainStyledAttributes(attrs,
				R.styleable.FlowIndicator);

		count = a.getInteger(R.styleable.FlowIndicator_count, 4);
		space = a.getDimension(R.styleable.FlowIndicator_space, 9);
		radius = a.getDimension(R.styleable.FlowIndicator_point_radius, 9);

		point_normal_color = a.getColor(
				R.styleable.FlowIndicator_point_normal_color, 0x000000);
		point_seleted_color = a.getColor(
				R.styleable.FlowIndicator_point_seleted_color, 0xffff07);

		int sum = attrs.getAttributeCount();
		if (Constans.DEBUG) {
			String str = "";
			for (int i = 0; i < sum; i++) {
				String name = attrs.getAttributeName(i);
				String value = attrs.getAttributeValue(i);
				str += "attr_name :" + name + ": " + value + "\n";
			}
			Log.i("attribute", str);
		}
		a.recycle();
	}

	public void setSeletion(int index) {
		this.seleted = index;
		invalidate();
	}

	public void setCount(int count) {
		this.count = count;
		invalidate();
	}

	public void next() {
		if (seleted < count - 1)
			seleted++;
		else
			seleted = 0;
		invalidate();
	}

	public void previous() {
		if (seleted > 0)
			seleted--;
		else
			seleted = count - 1;
		invalidate();
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		Paint paint = new Paint();
		paint.setAntiAlias(true);

		float width = (getWidth() - ((radius * 2 * count) + (space * (count - 1)))) / 2.f;

		for (int i = 0; i < count; i++) {
			if (i == seleted)
				paint.setColor(point_seleted_color);
			else
				paint.setColor(point_normal_color);
			canvas.drawCircle(width + getPaddingLeft() + radius + i
					* (space + radius + radius), getHeight() / 2, radius, paint);

		}
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		setMeasuredDimension(measureWidth(widthMeasureSpec),
				measureHeight(heightMeasureSpec));
	}

	private int measureWidth(int measureSpec) {
		int result = 0;
		int specMode = MeasureSpec.getMode(measureSpec);
		int specSize = MeasureSpec.getSize(measureSpec);

		if (specMode == MeasureSpec.EXACTLY) {
			result = specSize;
		} else {
			result = (int) (getPaddingLeft() + getPaddingRight()
					+ (count * 2 * radius) + (count - 1) * radius + 1);
			if (specMode == MeasureSpec.AT_MOST) {
				result = Math.min(result, specSize);
			}
		}
		return result;
	}

	private int measureHeight(int measureSpec) {
		int result = 0;
		int specMode = MeasureSpec.getMode(measureSpec);
		int specSize = MeasureSpec.getSize(measureSpec);

		if (specMode == MeasureSpec.EXACTLY) {
			result = specSize;
		} else {
			result = (int) (2 * radius + getPaddingTop() + getPaddingBottom() + 1);
			if (specMode == MeasureSpec.AT_MOST) {
				result = Math.min(result, specSize);
			}
		}
		return result;
	}

}


          在onMeasure函数中,系统帮我们测量的高度和宽度都是MATCH_PARNET,当我们设置明确的宽度和高度时,系统帮我们测量的结果就是我们设置的结果,当我们设置为WRAP_CONTENT,或者MATCH_PARENT系统帮我们测量的结果就是MATCH_PARENT的长度。所以,当设置了WRAP_CONTENT时,我们需要自己进行测量,即重写onMesure方法”:重写之前先了解MeasureSpec的specMode,一共三种类型:
EXACTLY:一般是设置了明确的值或者是MATCH_PARENT
AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT

UNSPECIFIED:表示子布局想要多大就多大,很少使用。

需要重写onMeasure方法,计算自定义view的大小。

         3,Gallery数据适配器类

public class GalleryAdapter extends BaseAdapter {
	Context mContext;
	int[] res = new int[] { R.drawable.t1, R.drawable.t2,
			R.drawable.t3, R.drawable.t1, R.drawable.t2,
			R.drawable.t3, R.drawable.t1, R.drawable.t2,
			R.drawable.t3 };

	public GalleryAdapter(Context cnt) {
		this.mContext = cnt;
	}

	@Override
	public int getCount() {
		// TODO Auto-generated method stub
		return res.length;
	}

	@Override
	public Object getItem(int arg0) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public long getItemId(int arg0) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public View getView(int arg0, View arg1, ViewGroup arg2) {
		// TODO Auto-generated method stub
		if (arg1 == null) {
			arg1 = LayoutInflater.from(mContext).inflate(R.layout.gallery_item,
					null);
		}
		ImageView img = (ImageView) arg1.findViewById(R.id.home_img);
		img.setImageResource(res[arg0]);
		return arg1;
	}
}

            4,主Activity

public class HomeActivity extends Activity {
	static final int SCROLL_ACTION = 0;
	int[] tags = new int[] { 0, 0, 0, 0, 0 };
	Gallery mGallery;
	GalleryAdapter mGalleryAdapter;
	FlowIndicator mMyView;
	Timer mTimer;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.home_activity);
		prepareView();
		mTimer = new Timer();
		mTimer.scheduleAtFixedRate(new MyTask(), 0, 4000);
	}

	private void prepareView() {
		mExpandableListView = (ExpandableListView) findViewById(R.id.expandableListView1);
		MyListAdapter adapter = new MyListAdapter();
		View header = LayoutInflater.from(this).inflate(R.layout.header_view,
				null);
		mGallery = (Gallery) header.findViewById(R.id.home_gallery);
		mMyView = (FlowIndicator) header.findViewById(R.id.myView);
		mGalleryAdapter = new GalleryAdapter(this);
		mMyView.setCount(mGalleryAdapter.getCount());
		mGallery.setAdapter(mGalleryAdapter);
		mGallery.setOnItemSelectedListener(new OnItemSelectedListener() {

			@Override
			public void onItemSelected(AdapterView<?> arg0, View arg1,
					int arg2, long arg3) {
				// TODO Auto-generated method stub
				mMyView.setSeletion(arg2);
			}

			@Override
			public void onNothingSelected(AdapterView<?> arg0) {
				// TODO Auto-generated method stub

			}
		});

	}

	private class MyTask extends TimerTask {
		@Override
		public void run() {
			mHandler.sendEmptyMessage(SCROLL_ACTION);
		}
	}

	Handler mHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			// TODO Auto-generated method stub
			super.handleMessage(msg);
			switch (msg.what) {
			case SCROLL_ACTION:
				 int curPos = mGallery.getSelectedItemPosition();
				 if (curPos < mGalleryAdapter.getCount() - 1) {
				 curPos++;
				 } else {
				 curPos = 0;
				 }
				/* mGallery.setLayoutAnimation(new LayoutAnimationController(
				 AnimationUtils.loadAnimation(HomeActivity.this,
				 R.anim.gallery_in)));*/
				 mGallery.setSelection(curPos, true);
				/*MotionEvent e1 = MotionEvent.obtain(SystemClock.uptimeMillis(),
						SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN,
						89.333336f, 265.33334f, 0);
				MotionEvent e2 = MotionEvent.obtain(SystemClock.uptimeMillis(),
						SystemClock.uptimeMillis(), MotionEvent.ACTION_UP,
						300.0f, 238.00003f, 0);

				mGallery.onFling(e1, e2, -1300, 0);*/
				break;

			default:
				break;
			}
		}
	};
}

实现图片定时自动切换和手动滑动切换。

            

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值