玩转Android 之 绚丽的自定义Gallery

試著忘記壹切 提交于 2020-03-02 06:18:45

暑期大学生博客分享大赛 - 2011 Android 成长篇

         本文参加第二届Google大学生暑期博客分享大赛 
         相信大家对Gallery这个控件是再喜爱不过了,用它可以做出很炫的效果,这得意于Android优良的架构和MVC设计模式的
便利。下面我会介绍一个比较炫的自定义的Gallery效果。先上效果图:

         如图,主要效果包括,中央文字变大,变亮,出现倒影,未选中项变小,变暗,gallery减慢滑动速度,循环gallery展
示。
         由于涉及公司项目,这里只贴关键代码和xml文档。
         首先默认的Gallery滑动时,滚动速度很快,会导致某些项一闪而过看不清楚,解决的办法是继承Gallery,自定义一个

CustomGallery类,覆盖Gallery的onFling()方法,让它返回false就行了,代码如下
package com.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.Gallery;

public class CustomGallery extends Gallery {

	public CustomGallery(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
	}
	public boolean onFling (MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
		return false;
	}

}


         接下来就是在xml文件中如何调用这个自定义的控件类的问题,解决方法很简单
<LinearLayout android:id="@+id/gallerylayout"
			android:layout_width="fill_parent" android:layout_height="fill_parent">
			<com.widget.CustomGallery
				android:layout_width="fill_parent" android:layout_height="wrap_content"
				android:spacing="10dip" android:unselectedAlpha="0.5" android:id="@+id/gallery"
				android:layout_marginTop="36dip" />
		</LinearLayout>


需要注意的是,Android支持的自定义控件类的构造函数,需要有Context和AttributeSet两个参数,否则会报异常!
另外
 android:unselectedAlpha="0.5"
这个属性可以设置未选中项的半透明度,设置为0.5,这样有突显选中项的效果。
         此时运行程序并不能显示我们自定义的Gallery,原因是,我们还没有向Gallery中添加数据,而向Gallery中添加数据需

要使用
Gallery的setAdapter方法,通过适配器来进行添加显示项,这里我们把大学的名称作为显示数据加入到适配器中,由于需要处理选

中项的倒影效果和变大效果,于是我们自定义一个Adapter来进行处理,代码如下
根据MVC,先是数据模型类University
public class University{
	private String name;  // 学校名称

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

然后是自定义的Adapter

public import java.util.ArrayList;
import com.model.Channel;
import com.util.BitmapUtil;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;


public class UniversityAdapter extends BaseAdapter {

	private Context context;
	private ArrayList<University> universityList;

	public UniversityAdapter(Context context, ArrayList<University> universityList) {
		this.context = context;
		this.universityList = universityList;
	}
        //这里返回一个较大整数是为了实现Gallery的循环播放
	@Override
	public int getCount() {
		// TODO Auto-generated method stub
		return Integer.MAX_VALUE;
	}

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

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

	private int select = 0;

	public void notifyDataSetChanged(int albumId) {
		select = albumId;
		super.notifyDataSetChanged();
	}
	public View getView(int position, View convertView, ViewGroup parent) {
		// TODO Auto-generated method stub
		ImageView imageView = new ImageView(context);//初始化ImageView,用来显示各项
		if (select == position) {//当此项是选中项时,对起进行特殊处理
			University pro = universityList.get(position % universityList.size());//要实现循环播放,这

里需要对数据大小进行求余
			imageView.setImageBitmap(BitmapUtil.createReflectedImage(BitmapUtil
					.createTxtImage(pro.getName(), 28)));//这里通过自定义的BitmapUtil类中的两个

方法,实现了倒影效果
		} else {
			University pro = universityList.get(position % universityList.size());
			imageView.setImageBitmap(BitmapUtil.createTxtImage(pro.getName(),
					22));//这设置文字大小为22。实现了未选中项的变小效果
		}
		return imageView;
	}

上面代码中的BitmapUtil是封装好的Bitmap处理工具类,包括了传入文字和字体大小,返回绘制好的Bitmap 和传入Bitmap返回下方

加入了倒影效果的Bitmap的函数。代码如下
package com.util;

import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Shader.TileMode;

public class BitmapUtil {

	public static Bitmap createTxtImage(String txt, int txtSize) {
		Bitmap mbmpTest = Bitmap.createBitmap(txt.length() * txtSize + 4,
				txtSize + 4, Config.ARGB_8888);
		Canvas canvasTemp = new Canvas(mbmpTest);
		Paint p = new Paint();
		p.setAntiAlias(true);
		p.setColor(Color.WHITE);
		p.setTextSize(txtSize);
		canvasTemp.drawText(txt, 2, txtSize - 2, p);
		return mbmpTest;
	}
	
	public static Bitmap createReflectedImage(Bitmap originalImage) {
		// The gap we want between the reflection and the original image
		final int reflectionGap = 0;

		int width = originalImage.getWidth();
		int height = originalImage.getHeight();

		// This will not scale but will flip on the Y axis
		Matrix matrix = new Matrix();
		matrix.preScale(1, -1);

		// Create a Bitmap with the flip matrix applied to it.
		// We only want the bottom half of the image
		Bitmap reflectionImage = Bitmap.createBitmap(originalImage, 0,
				height / 2, width, height / 2, matrix, false);

		// Create a new bitmap with same width but taller to fit reflection
		Bitmap bitmapWithReflection = Bitmap.createBitmap(width,
				(height + height / 2), Config.ARGB_8888);

		// Create a new Canvas with the bitmap that's big enough for
		// the image plus gap plus reflection
		Canvas canvas = new Canvas(bitmapWithReflection);
		// Draw in the original image
		canvas.drawBitmap(originalImage, 0, 0, null);
		// Draw in the gap
		Paint defaultPaint = new Paint();
		canvas.drawRect(0, height, width, height + reflectionGap, defaultPaint);
		// Draw in the reflection
		canvas.drawBitmap(reflectionImage, 0, height + reflectionGap, null);

		// Create a shader that is a linear gradient that covers the reflection
		Paint paint = new Paint();
		LinearGradient shader = new LinearGradient(0,
				originalImage.getHeight(), 0, bitmapWithReflection.getHeight()
						+ reflectionGap, 0x70ffffff, 0x00ffffff, TileMode.CLAMP);
		// Set the paint to use this shader (linear gradient)
		paint.setShader(shader);
		// Set the Transfer mode to be porter duff and destination in
		paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
		// Draw a rectangle using the paint with our linear gradient
		canvas.drawRect(0, height, width, bitmapWithReflection.getHeight()
				+ reflectionGap, paint);

		return bitmapWithReflection;
	}
}


最后就是主界面代码中对Gallery的调用了,关键代码如下
private CustomGallery gallery;
	private UniversityAdapter pAdapter;
	private ArrayList<University> universityList = new ArrayList<University>();
        private void init(){
		pAdapter = new UniversityAdapter(MainActivity.this, universityList);//初始化我们自定义的Adapter
		University p = new University();
		p.setName("电子科技大学");
		universityList .add(p);
		University p1 = new University();
		p1.setName("清华大学");
		universityList .add(p1);
		University p2 = new University();
		p2.setName("北京大学");
		universityList .add(p2);
		gallery.setAdapter(pAdapter);//设置Gallery显示的内容
		gallery.setSelection(Integer.MAX_VALUE / 2);//通过setSelection() 可以设置当前选中的元素,这里我们将

其设置在中间
		gallery.setOnItemSelectedListener(this);//这里对Item项进行监听,以实现刷新显示的效果
       }

@Override
public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2,
			long arg3) {
	// TODO Auto-generated method stub
	pAdapter.notifyDataSetChanged(arg2);//arg2会返回当前选中项的位置,调用此方法,通知更新
}


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

代码贴完了,有疑问的可以发我邮件,邮箱是uestccokey@gmail.com
希望大家最后都能把程序跑起来,做出更好更实用的效果。

各位路过的哥们儿们,帮小弟投个票吧,http://www.google.com/intl/zh-CN/daxue/blog/vote.html#tab2
下面选李可,电子科技大学,谢谢了,哈哈
下一期我们将会讲解如何通过xml更简单的自定义各种控件,希望大家继续支持 
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!