在上面5篇文章中,我们已经把我们的安卓市场的框架搭建完成了,虽然说,我们的框架搭建的很简陋,但是对于我这个没有过公司经验的学生来说,自己感觉还好,所以,希望大家有什么建议就给我提出来,让我能够长长见识,多学习一下。
在这一篇中,我们主要完成我们的Home界面的开发。在此之前,我们先回顾一下我们在这里用到的控件以及其基础部分。
我们在首页中用到的控件主要有Gallery,ListView,在这里,我们先来回顾一下Gallery的基础知识。
Gallery是一个内部元素可以水平滚动,并且可以把当前选择子元素定位在中心的布局组件。在这里我们需要重写Gallery组件,同时,我们的组件可以实现手指滑动以及item点击的功能,同时呢,在我们的Gallery的下面有一个圆点容器,用于表示现在显示的是哪一张图片。
首先,布局是非常重要的,我们的布局就是上面一个Gallery组件,下面是一个圆点容器,我们使用LinearLayout。我们把这个布局放在我们之前写过的activity_home.xml布局文件中。
<RelativeLayout
android:id="@+id/rl_advers"android:layout_width="match_parent"android:layout_height="100dp"android:layout_below="@id/rl_head" ><com.sdu.ui.AdGallery
android:id="@+id/app_advers"android:layout_width="match_parent"android:layout_height="wrap_content" /><LinearLayout
android:id="@+id/ovalLayout"android:layout_width="match_parent"android:layout_height="10dip"android:layout_below="@+id/app_advers"android:background="#FFFFFF"android:gravity="center"android:orientation="horizontal" ></LinearLayout></RelativeLayout>
其中com.sdu.ui.AdGallery是我们自定义的组件。一会我们会讲到,同时,在我们的首页部分还有一个顶部的搜索框,这个布局相对比较简单,我们来看一下。
<RelativeLayout
android:id="@+id/rl_head"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@color/mbarcolor" ><RelativeLayout
android:id="@+id/rl_in_head"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentTop="true"android:layout_margin="5dip" ><TextView
android:id="@+id/tv_contact"android:layout_width="40dip"android:layout_height="40dp"android:background="@drawable/contact_press"android:clickable="true" /><RelativeLayout
android:id="@+id/rl_search"android:layout_width="match_parent"android:layout_height="40dip"android:layout_marginLeft="8dp"android:layout_toRightOf="@id/tv_contact"android:background="@drawable/shape_rectangle" ><ImageView
android:id="@+id/iv_search"android:layout_width="30dp"android:layout_height="30dp"android:layout_centerVertical="true"android:background="@drawable/search" /><TextView
android:id="@+id/tv_search"android:layout_width="wrap_content"android:layout_height="30dp"android:layout_centerVertical="true"android:layout_marginLeft="5dp"android:layout_toRightOf="@id/iv_search"android:gravity="center_vertical"android:text="@string/tv_search_text"android:textColor="@color/lightgrey"android:textSize="20sp" /><ImageView
android:id="@+id/iv_dia"android:layout_width="30dp"android:layout_height="30dp"android:layout_alignParentRight="true"android:layout_marginRight="5dp"android:background="@drawable/diecode" /></RelativeLayout></RelativeLayout><RelativeLayout
android:id="@+id/rl_blank"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_below="@id/rl_in_head" ></RelativeLayout></RelativeLayout>
在这里要说一下的可能就是我们的圆角形的样式shape_rectangle。
在我们的res/drawable文件夹下面我们创建shape_rectangle.xml文件,他所依赖的文件有round_rectangle_bg_pressed.xml和round_rectangle_bg.xml。
我们先把我们的shape_rectangle.xml贴上:
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true" android:drawable="@drawable/round_rectangle_bg_pressed" /> <!-- pressed --> <item android:state_focused="true" android:drawable="@drawable/round_rectangle_bg_pressed" /> <!-- focused --> <item android:state_selected="true" android:drawable="@drawable/round_rectangle_bg_pressed" /> <!-- selected --> <item android:drawable="@drawable/round_rectangle_bg" /> <!-- default bg_list_item_normal --> </selector>
这是一个选择器,也就是当控件被点击的时候的样式和不被点击的时候的样式的一个选择器。
下面我们来看一下round_rectangle_bg_pressed.xml。
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" ><!-- android:shape="" 表示是圆角矩形还是椭圆等等 --> <solid android:color="#ffffff"/> <!-- 背景颜色 --> <!-- padding 表示内部空间距离背景图片内部边距 的距离 --> <padding android:left="10dp" android:top="5dp" android:right="10dp" android:bottom="5dp" /> <stroke android:width="1dp" android:color="#cecece"/> <!-- 图片边框属性 --> <corners android:radius="10dp" /> <!-- 圆角的程度 --> <gradient android:startColor="#ffffff" android:centerColor="#ffffff" android:endColor="#ffffff" android:type="linear" android:angle="90" android:centerX="0.5" android:centerY="0.5" /> </shape>
在这里我们定义了一个shape,也就是形状,具体的信息我们已经在注释中解释了。
还有一个就是round_rectangle_bg.xml
<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="rectangle" ><!-- android:shape="" 表示是圆角矩形还是椭圆等等 --><solid android:color="#ffffff" /><!-- 背景颜色 --><!-- padding 表示内部空间距离背景图片内部边距 的距离 --><padding
android:bottom="5dp"android:left="10dp"android:right="10dp"android:top="5dp" /><stroke
android:width="1dp"android:color="#cecece" /><!-- 图片边框属性 --><corners android:radius="10dp" /><!-- 圆角的程度 --><gradient
android:angle="90"android:centerColor="#ffffff"android:centerX="0.5"android:centerY="0.5"android:endColor="#ffffff"android:startColor="#ffffff"android:type="linear" /></shape>
这样的话,上面的搜索框已经完成,现在我们来看一下我们如何继承自Gallery来自定义一个广告Gallery。
首先我们需要继承自Gallery,同时,我们还需要实现OnItemClickListener,OnItemSelectListener和OnTouchListener.
其次我们需要重载父类的三个构造方法,以便能够在xml文件中使用该控件.
public AdGallery(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);}public AdGallery(Context context) {super(context);}public AdGallery(Context context, AttributeSet attrs) {super(context, attrs);}
我们来看一下整体的代码,这个注释非常清楚。
package com.sdu.ui;import java.util.ArrayList;import java.util.List;import java.util.Timer;import java.util.TimerTask;import net.tsz.afinal.FinalBitmap;import android.annotation.SuppressLint;import android.content.Context;import android.os.Handler;import android.os.Message;import android.util.AttributeSet;import android.view.KeyEvent;import android.view.MotionEvent;import android.view.View;import android.view.View.OnTouchListener;import android.view.ViewGroup;import android.widget.AdapterView;import android.widget.BaseAdapter;import android.widget.Gallery;import android.widget.ImageView;import android.widget.LinearLayout;/*** 无限滚动广告栏组件*/@SuppressWarnings("deprecation")public class AdGallery extends Gallery implementsandroid.widget.AdapterView.OnItemClickListener,android.widget.AdapterView.OnItemSelectedListener, OnTouchListener {/** 显示的Activity */private Context mContext;/** 条目单击事件接口 */private AdversOnItemClickListener mAdversOnItemClickListener;/** 图片切换时间 */private int mSwitchTime;/** 自动滚动的定时器 */private Timer mTimer;/** 圆点容器 */private LinearLayout mOvalLayout;/** 当前选中的数组索引 */private int curIndex = 0;/** 上次选中的数组索引 */private int oldIndex = 0;/** 圆点选中时的背景ID */private int mFocusedId;/** 圆点正常时的背景ID */private int mNormalId;/** 图片资源ID组 */private int[] mAdsId;/** 图片网络路径数组 */private String[] mUris;/** ImageView组 */List<ImageView> listImgs;public AdGallery(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);}public AdGallery(Context context) {super(context);}public AdGallery(Context context, AttributeSet attrs) {super(context, attrs);}/*** @param context* 显示的Activity ,不能为null* @param mris* 图片的网络路径数组 ,为空时 加载 adsId* @param adsId* 图片组资源ID ,测试用* @param switchTime* 图片切换时间 写0 为不自动切换* @param ovalLayout* 圆点容器 ,可为空* @param focusedId* 圆点选中时的背景ID,圆点容器可为空写0* @param normalId* 圆点正常时的背景ID,圆点容器为空写0*/public void start(Context context, String[] mris, int[] adsId,int switchTime, LinearLayout ovalLayout, int focusedId, int normalId) {this.mContext = context;this.mUris = mris;this.mAdsId = adsId;this.mSwitchTime = switchTime;this.mOvalLayout = ovalLayout;this.mFocusedId = focusedId;this.mNormalId = normalId;ininImages();// 初始化图片组setAdapter(new AdAdapter());this.setOnItemClickListener(this);this.setOnTouchListener(this);this.setOnItemSelectedListener(this);this.setSoundEffectsEnabled(false);this.setAnimationDuration(700); // 动画时间this.setUnselectedAlpha(1); // 未选中项目的透明度// 不包含spacing会导致onKeyDown()失效!!! 失效onKeyDown()前先调用onScroll(null,1,0)可处理setSpacing(0);// 取靠近中间 图片数组的整倍数setSelection((getCount() / 2 / listImgs.size()) * listImgs.size()); // 默认选中中间位置为起始位置setFocusableInTouchMode(true);initOvalLayout();// 初始化圆点startTimer();// 开始自动滚动任务}/** 初始化图片组 */private void ininImages() {listImgs = new ArrayList<ImageView>(); // 图片组int len = mUris != null ? mUris.length : mAdsId.length;for (int i = 0; i < len; i++) {ImageView imageview = new ImageView(mContext); // 实例化ImageView的对象imageview.setScaleType(ImageView.ScaleType.FIT_XY); // 设置缩放方式imageview.setLayoutParams(new Gallery.LayoutParams(Gallery.LayoutParams.MATCH_PARENT,Gallery.LayoutParams.MATCH_PARENT));if (mUris == null) {// 本地加载图片imageview.setImageResource(mAdsId[i]); // 为ImageView设置要显示的图片} else { // 网络加载图片FinalBitmap.create(mContext).display(imageview, mUris[i], imageview.getWidth(),imageview.getHeight(), null, null);}listImgs.add(imageview);}}/** 初始化圆点 */private void initOvalLayout() {if (mOvalLayout != null && listImgs.size() < 2) {// 如果只有一第图时不显示圆点容器mOvalLayout.getLayoutParams().height = 0;} else if (mOvalLayout != null) {// 圆点的大小是 圆点窗口的 70%;int Ovalheight = (int) (mOvalLayout.getLayoutParams().height * 0.7);// 圆点的左右外边距是 圆点窗口的 20%;int Ovalmargin = (int) (mOvalLayout.getLayoutParams().height * 0.2);android.widget.LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(Ovalheight, Ovalheight);layoutParams.setMargins(Ovalmargin, 0, Ovalmargin, 0);for (int i = 0; i < listImgs.size(); i++) {View v = new View(mContext); // 员点v.setLayoutParams(layoutParams);v.setBackgroundResource(mNormalId);mOvalLayout.addView(v);}// 选中第一个mOvalLayout.getChildAt(0).setBackgroundResource(mFocusedId);}}/** 无限循环适配器 */class AdAdapter extends BaseAdapter {@Overridepublic int getCount() {if (listImgs.size() < 2)// 如果只有一张图时不滚动return listImgs.size();return Integer.MAX_VALUE;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {return listImgs.get(position % listImgs.size()); // 返回ImageView}@Overridepublic Object getItem(int position) {return null;}@Overridepublic long getItemId(int position) {return position;}}public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,float velocityY) {int kEvent;if (isScrollingLeft(e1, e2)) { // 检查是否往左滑动kEvent = KeyEvent.KEYCODE_DPAD_LEFT;} else { // 检查是否往右滑动kEvent = KeyEvent.KEYCODE_DPAD_RIGHT;}onKeyDown(kEvent, null);return true;}/** 检查是否往左滑动 */private boolean isScrollingLeft(MotionEvent e1, MotionEvent e2) {return e2.getX() > (e1.getX() + 50);}@Overridepublic boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,float distanceY) {return super.onScroll(e1, e2, distanceX, distanceY);}@Overridepublic boolean onTouch(View v, MotionEvent event) {if (MotionEvent.ACTION_UP == event.getAction()|| MotionEvent.ACTION_CANCEL == event.getAction()) {startTimer();// 开始自动滚动任务} else {stopTimer();// 停止自动滚动任务}return false;}/** 图片切换事件 */@Overridepublic void onItemSelected(AdapterView<?> arg0, View arg1, int position,long arg3) {curIndex = position % listImgs.size();if (mOvalLayout != null && listImgs.size() > 1) { // 切换圆点mOvalLayout.getChildAt(oldIndex).setBackgroundResource(mNormalId); // 圆点取消mOvalLayout.getChildAt(curIndex).setBackgroundResource(mFocusedId);// 圆点选中oldIndex = curIndex;}}@Overridepublic void onNothingSelected(AdapterView<?> arg0) {}/** 项目点击事件 */@Overridepublic void onItemClick(AdapterView<?> arg0, View arg1, int position,long arg3) {if (mAdversOnItemClickListener != null) {mAdversOnItemClickListener.onItemClick(curIndex);}}/** 设置项目点击事件监听器 */public void setAdversOnItemClickListener(AdversOnItemClickListener listener) {mAdversOnItemClickListener = listener;}/** 项目点击事件监听器接口 */public interface AdversOnItemClickListener {/*** @param curIndex* //当前条目在数组中的下标*/void onItemClick(int curIndex);}/** 停止自动滚动任务 */public void stopTimer() {if (mTimer != null) {mTimer.cancel();mTimer = null;}}/** 开始自动滚动任务 图片大于1张才滚动 */public void startTimer() {if (mTimer == null && listImgs.size() > 1 && mSwitchTime > 0) {mTimer = new Timer();mTimer.schedule(new TimerTask() {public void run() {handler.sendMessage(handler.obtainMessage(1));}}, mSwitchTime, mSwitchTime);}}/** 处理定时滚动任务 */@SuppressLint("HandlerLeak")private Handler handler = new Handler() {@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);// 不包含spacing会导致onKeyDown()失效!!!// 失效onKeyDown()前先调用onScroll(null,1,0)可处理onScroll(null, null, 1, 0);onKeyDown(KeyEvent.KEYCODE_DPAD_RIGHT, null);}};}
这样的话,我们整体的广告界面就完成了,在这里,我们使用了AFinal的开源框架来加载网络图片。
然后在我们的HomeActivity中,初始化该控件以及添加测试数据。
package com.sdu.activities;import net.tsz.afinal.FinalBitmap;import com.sdu.androidmarket.R;import com.sdu.ui.AdGallery;import com.sdu.utils.AppLog;import android.content.Intent;import android.view.View;import android.widget.AdapterView;import android.widget.ImageView;import android.widget.LinearLayout;import android.widget.TextView;import android.view.Window;public class HomeActivity extends BaseActivity {private TextView tv_search;private TextView tv_contact;private ImageView iv_dia;private AdGallery app_advers;private LinearLayout ovalLayout; // 圆点容器/** 图片id的数组,本地测试用 */private int[] imageId = new int[] { R.drawable.test, R.drawable.test,R.drawable.test, R.drawable.test };/** 图片网络路径数组 */private String[] mris = {"https://img-my.csdn.net/uploads/201312/14/1386989803_3335.PNG","https://img-my.csdn.net/uploads/201312/14/1386989613_6900.jpg","https://img-my.csdn.net/uploads/201312/14/1386989802_7236.PNG" };@Overridepublic void initWidget() {requestWindowFeature(Window.FEATURE_NO_TITLE);setContentView(R.layout.activity_home);FinalBitmap.create(this); // android 框架 这里用于加载网络图片 tv_search = (TextView)findViewById(R.id.tv_search);tv_contact = (TextView)findViewById(R.id.tv_contact);iv_dia = (ImageView)findViewById(R.id.iv_dia);tv_search.setOnClickListener(this);tv_contact.setOnClickListener(this);iv_dia.setOnClickListener(this);app_advers = (AdGallery)findViewById(R.id.app_advers);ovalLayout = (LinearLayout) findViewById(R.id.ovalLayout);// 获取圆点容器// 第二和第三参数 2选1 ,参数2为 图片网络路径数组 ,参数3为图片id的数组,本地测试用 ,2个参数都有优先采用 参数2app_advers.start(this, mris, imageId, 3000, ovalLayout,R.drawable.dot_focused, R.drawable.dot_normal);app_advers.setAdversOnItemClickListener(new AdGallery.AdversOnItemClickListener() {public void onItemClick(int curIndex) {AppLog.error("点击的图片下标为:" + curIndex);// System.out.println(curIndex);}});}@Overridepublic void widgetClick(View v) {Intent intent = null; switch(v.getId()){case R.id.tv_search:intent = new Intent(HomeActivity.this,SearchActivity.class);startActivity(intent);break;case R.id.tv_contact:intent = new Intent(HomeActivity.this,MeActivity.class);startActivity(intent);break;case R.id.iv_dia:intent = new Intent(HomeActivity.this,DiacodeActivity.class);startActivity(intent);break;}}@Overridepublic void widgetItemClick(AdapterView<?> parent, View view, int position,long id) {}}
这样的话,我们的广告组件就完成了。
我们来看一下整体的效果。
我的博客地址:www.tinyhug.tk,谢谢大家参观!!