热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

android自定义动态滚动tab+viewpager+fragment

近来一段时间,项目有点空闲,就总结总结开发中常用的东西,封装封装,提炼提炼,写写博客与大家共勉,有什么不对的或者更好的思路欢迎大家广开言路~~在android开发中,常见的ui框架中,很经典的一种就

近来一段时间,项目有点空闲,就总结总结开发中常用的东西,封装封装,提炼提炼,写写博客与大家共勉,有什么不对的或者更好的思路欢迎大家广开言路~~

 

在android开发中,常见的ui框架中,很经典的一种就是如图所示:

 

整体是自定义的支持水平滚动的tab+左右滑动viewpager+fragment

入口activity  HorizontalScrollViewTestActivity:

package com.example.webservice.widget.ColumnHorizontalScrollView;

import java.util.ArrayList;
import java.util.List;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.util.Log;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.Toast;

import com.example.webservice.R;
import com.example.webservice.bean.TabCode;
import com.example.webservice.widget.scrollTab.ScrollTabs;
/**
* 用来测试水平滚动的tab的实例activity
* @author xhf
*
*/
public class HorizontalScrollViewTestActivity extends FragmentActivity{

private ViewPager mViewPager;

/** 自定义HorizontalScrollView */
private ColumnHorizontalScrollView mColumnHorizontalScrollView;
/**
* 用来添加tab的root布局
*/
LinearLayout mRadioGroup_content;

RelativeLayout rl_column;

/** 左阴影部分*/
public ImageView shade_left;

/** 右阴影部分 */
public ImageView shade_right;

/** 屏幕宽度 */
private int mScreenWidth = 0;

private ScrollTabs stTabs;

@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.view_column_horizontal_scroll);
initView();

}

private void initView()
{
mColumnHorizOntalScrollView= (ColumnHorizontalScrollView)findViewById(R.id.mColumnHorizontalScrollView);

rl_column = (RelativeLayout) findViewById(R.id.rl_column);
mViewPager = (ViewPager) findViewById(R.id.viewPager);
//viewpager每次显示出来一个fragment时,都会把旁边的一个页面也预加载了,当然你可以控制预加载的页面的数量
mViewPager.setOffscreenPageLimit(0);//不预加载
shade_left = (ImageView) findViewById(R.id.shade_left);
shade_right = (ImageView) findViewById(R.id.shade_right);

stTabs = (ScrollTabs) findViewById(R.id.st_tabs);
mColumnHorizontalScrollView.setParam(this, mScreenWidth, stTabs, shade_left, shade_right, rl_column);
List lists=new ArrayList();
TabCode tc1=new TabCode(1000,"科技");
TabCode tc2=new TabCode(1001,"财经");
TabCode tc3=new TabCode(1002,"新闻");
TabCode tc4=new TabCode(1003,"原创");
TabCode tc5=new TabCode(1004,"体育");
lists.add(tc1);
lists.add(tc2);
lists.add(tc3);
lists.add(tc4);
lists.add(tc5);

//将activity传递到自定义view中,以获取screenWidth
stTabs.setParams(HorizontalScrollViewTestActivity.this,lists);
//tab item点击事件
stTabs.setOnItemClickListener(new ScrollTabs.OnItemClickListener() {        @Override        public void onItemClick(int index,TabCode tc) {            //重写底部的数据值            //envMOnitorInfo= sysLoadMonitorInfos.get(index);            //loadStatisticsData(envMonitorInfo.getStatisticsData(), showDataType);           Toast.makeText(HorizontalScrollViewTestActivity.this, String.valueOf(tc.getCode()), Toast.LENGTH_LONG).show();        }    });        List fragments=new ArrayList();    for(int i=0;i


activity布局文件view_column_horizontal_scroll:

    xmlns:tools="http://schemas.android.com/tools"
android:layout_
android:layout_
android:background="@color/tx_gray1"
android:orientation="vertical" >

android:id="@+id/rl_column"
android:layout_
android:layout_
android:layout_weight="1.0" >

android:id="@+id/mColumnHorizontalScrollView"
android:layout_
android:layout_
android:scrollbars="none">

android:id="@+id/st_tabs"
android:layout_
android:layout_
android:layout_marginLeft="@dimen/dip15"
android:layout_marginRight="@dimen/dip15"
android:background="@android:color/transparent"
android:orientation="vertical" >



android:id="@+id/shade_left"
android:layout_
android:layout_
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:background="@drawable/channel_leftblock"
android:visibility="gone" />

android:id="@+id/shade_right"
android:layout_
android:layout_
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:background="@drawable/channel_rightblock"
android:visibility="gone" />





android:id="@+id/viewPager"
android:layout_
android:layout_
android:layout_marginLeft="@dimen/dip5"
android:layout_marginRight="@dimen/dip5"
android:layout_marginTop="@dimen/dip10"
android:layout_marginBottom="@dimen/dip10" />


首先是自定义的水平滚动的头部tabview相关类 :

package com.example.webservice.widget.ColumnHorizontalScrollView;

import android.app.Activity;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;

/**
* 自定义水平滚动的view,带左右阴影效果
* @author xuhaifeng
*
*/
public class ColumnHorizontalScrollView extends HorizontalScrollView {
/** 传入整体布局 */
private View ll_content;
/** 传入拖动栏布局 */
private View rl_column;
/** 左阴影图片 */
private ImageView leftImage;
/** 右阴影图片 */
private ImageView rightImage;
/** 屏幕宽度 */
private int mScreenWitdh = 0;
/** 父类的活动activity */
private Activity activity;

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

public ColumnHorizontalScrollView(Context context, AttributeSet attrs) {
super(context, attrs);

}

public ColumnHorizontalScrollView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
}

/**
* 在拖动的时候执行,主要是为了拖动前后加上阴影效果图
* */
@Override
protected void onScrollChanged(int paramInt1, int paramInt2, int paramInt3,
int paramInt4) {
// TODO Auto-generated method stub
super.onScrollChanged(paramInt1, paramInt2, paramInt3, paramInt4);
shade_ShowOrHide();
if (!activity.isFinishing() && ll_content != null && leftImage != null
&& rightImage != null && rl_column != null) {
if (ll_content.getWidth() <= mScreenWitdh) {
leftImage.setVisibility(View.GONE);
rightImage.setVisibility(View.GONE);
}
} else {
return;
}
if (paramInt1 == 0) {
leftImage.setVisibility(View.GONE);
rightImage.setVisibility(View.VISIBLE);
return;
}
if (ll_content.getWidth() - paramInt1 + rl_column.getLeft() == mScreenWitdh) {
leftImage.setVisibility(View.VISIBLE);
rightImage.setVisibility(View.GONE);
return;
}
leftImage.setVisibility(View.VISIBLE);
rightImage.setVisibility(View.VISIBLE);
}

/**
* 传入父类布局中的资源文件
* */
public void setParam(Activity activity, int mScreenWitdh, View paramView1,
ImageView paramView2, ImageView paramView3, View paramView5) {
this.activity = activity;
this.mScreenWitdh = mScreenWitdh;
ll_cOntent= paramView1;
leftImage = paramView2;
rightImage = paramView3;
rl_column = paramView5;
}

/**
* 判断左右阴影的显示隐藏效果
* */
public void shade_ShowOrHide() {
if (!activity.isFinishing() && ll_content != null) {
measure(0, 0);
// 如果整体宽度小于屏幕宽度的话,那左右阴影都隐藏
if (mScreenWitdh >= getMeasuredWidth()) {
leftImage.setVisibility(View.GONE);
rightImage.setVisibility(View.GONE);
}
} else {
return;
}
// 如果滑动在最左边时候,左边阴影隐藏,右边显示
if (getLeft() == 0) {
leftImage.setVisibility(View.GONE);
rightImage.setVisibility(View.VISIBLE);
return;
}
// 如果滑动在最右边时候,左边阴影显示,右边隐藏
if (getRight() == getMeasuredWidth() - mScreenWitdh) {
leftImage.setVisibility(View.VISIBLE);
rightImage.setVisibility(View.GONE);
return;
}
// 否则,说明在中间位置,左、右阴影都显示
leftImage.setVisibility(View.VISIBLE);
rightImage.setVisibility(View.VISIBLE);
}

}

 

package com.example.webservice.widget.scrollTab;

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.content.Context;
import android.graphics.Color;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.example.webservice.R;
import com.example.webservice.bean.TabCode;
/**
*
*

Title:带滑动效果的tab切换控件


*

Description:


* @author xhf
* @date 2014-12-17
*/
public class ScrollTabs extends LinearLayout {

/**
* 滑动图片
*/
private ImageView cursor;
/**
* tab 页外围布局 linerLayout
*/
private LinearLayout tabsLinerLayout;
/**
* 每一屏显示最大的tab页数
*/
private final static int MAX_TABS_NUM = 4;

/**
* 所有tab页的存储
*/
private static List tabsList = null;

/**
* 当前选中的tab
*/
private int currentIndex = 0;

private int layoutWidth;

private OnItemClickListener onItemClickListener;

private boolean isFirstIn = true;
/**
* 父类activity
*/
private Activity mActivity;

/**
* 头部tab标签页数据源
*/
private List lists;

public ScrollTabs(Context context) {
this(context, null);
}

public ScrollTabs(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater inflater = LayoutInflater.from(getContext());
LinearLayout tabLinerLayout = (LinearLayout) inflater.inflate(
R.layout.layout_tab, this, true);
tabsLinerLayout = (LinearLayout) tabLinerLayout
.findViewById(R.id.tabLayoutTabs);
cursor = (ImageView) tabLinerLayout.findViewById(R.id.cursor);
}

public ScrollTabs(Context context, AttributeSet attrs, int defStyle) {
this(context, attrs);
}

public void setParams(Activity activity,List tcs)
{
this.mActivity=activity;
this.lists=tcs;
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int specModeWidth = MeasureSpec.getMode(widthMeasureSpec);
if( isFirstIn) {
initView();
}
}

private void initView() {
DisplayMetrics dm = new DisplayMetrics();
mActivity.getWindowManager().getDefaultDisplay().getMetrics(dm);
layoutWidth = dm.widthPixels;
Log.i("ScrollTabs", "ScrollTabs getMeasuredWidth" + layoutWidth);
tabsList = new ArrayList();
for (int i = 0; iaddNewTab(lists.get(i));
}
if (cursor != null) {
cursor.setLayoutParams(new FrameLayout.LayoutParams(layoutWidth
/ getTabs(), cursor.getLayoutParams().height));
}
// 设置默认项
if (isFirstIn) {
changeTabCursor(0);
isFirstIn = false;
}
}


/**
* 添加新的tab页
* @param weekIndex
*
*/
public void addNewTab(TabCode tc) {
LinearLayout tabView = getNewTab(tc);
if(tabsLinerLayout!=null) {
tabsLinerLayout.addView(tabView);
}
tabsList.add(tabView);
}



/**
* 生成一个新的tab项
* @param date
* @param weekIndex
* @return
*/
public LinearLayout getNewTab(TabCode tc) {
LayoutInflater inflater = LayoutInflater.from(getContext());
LinearLayout tabLinerLayout = (LinearLayout) inflater.inflate(R.layout.item_tab, null);
if(tabLinerLayout!=null) {
int index = tabsList.size();
tabLinerLayout.setOnClickListener(new TabOnClickListener(index,tc));
TextView txDate = (TextView) tabLinerLayout.findViewById(R.id.tvTabContent);
if(txDate!=null) {
txDate.setText(tc.getName());
}
}
return tabLinerLayout;
}

/**
* 每个tab项点击事件
* @author xhf
*
*/
public class TabOnClickListener implements OnClickListener {

private int index;

private TabCode tc;

public TabOnClickListener(int index,TabCode tc) {
this.index = index;
this.tc=tc;
}

@Override
public void onClick(View v) {
changeTabCursor(index);
if(onItemClickListener!=null) {
onItemClickListener.onItemClick(index,tc);
}
}
}

public interface OnItemClickListener {
public void onItemClick(int index,TabCode tc);
};


/**
* 选中tab表头的变化效果
*
*/
public void changeTabCursor(int targetIndex) {
int currentPostion = getMoveStep(currentIndex);
int targetPostion = getMoveStep(targetIndex);
// 设置选中tab页的字体颜色
for (int i = 0; i LinearLayout tabView = (LinearLayout) tabsList.get(i);
if(tabView!=null) {
TextView txDate = (TextView) tabView.getChildAt(0);
txDate.setWidth(getTabWidth());
if (i == targetIndex) {
txDate.setTextColor(Color.WHITE);
txDate.setTextSize(TypedValue.COMPLEX_UNIT_PX, getResources()
.getDimension(R.dimen.sp20));
} else if(i==currentIndex) {
txDate.setTextColor(getResources().getColor(
R.color.defect_text_light_orange));
txDate.setTextSize(TypedValue.COMPLEX_UNIT_PX, getResources()
.getDimension(R.dimen.sp17));
}
}
}
Animation animation = new TranslateAnimation(currentPostion,
targetPostion, 0, 0);
animation.setFillAfter(true);
animation.setDuration(300);
if(cursor!=null) {
cursor.startAnimation(animation);
}
currentIndex = targetIndex;
}

/**
* 滑动图片移动位置
*
* @param steps
* @return
*/
private int getMoveStep(int steps) {
int moveStep = 0;
if (steps != 0) {
moveStep = getTabWidth() * steps;
} else {
moveStep = 0;
}
return moveStep;
}

/**
* 每一个tab页宽度
*
* @return
*/
private int getTabWidth() {
return (layoutWidth / getTabs());
}

/**
* 获取tab长度
* @return
*/
private int getTabs() {
return tabsList.size() > MAX_TABS_NUM ? MAX_TABS_NUM : tabsList.size();
}

public void setOnItemClickListener(OnItemClickListener itemClickListener) {
this.OnItemClickListener= itemClickListener;
}
}

涉及到的xml布局:


android:layout_
android:layout_
android:background="@android:color/transparent"
android:orientation="vertical"
android:gravity="center" >

android:id="@+id/tabLayoutTabs"
android:layout_
android:layout_
android:baselineAligned="false"
android:gravity="center"
android:orientation="horizontal"
android:layout_gravity="center">





 

接下来是每个tab item的布局:


android:id="@+id/ll_child"
android:layout_
android:layout_
android:gravity="center"
android:orientation="vertical"
android:layout_gravity="center" >

android:id="@+id/tvTabContent"
android:layout_
android:layout_
android:gravity="center"
android:singleLine="true"
android:textColor="@color/defect_text_light_orange"
android:textSize="12sp"
android:text="12.20" />




实际上在开发过程中每个tab item的信息也是从服务端获取的一个带有id和value的bean实体类,所以在此我也做了实体类封装:

package com.example.webservice.bean;


/**
* 头部滚动tab每个tabItem实体bean类
* @author xhf
*
*/
public class TabCode {

private int code;

private String name;

public int getCode() {
return code;
}

public void setCode(int code) {
this.code = code;
}

public String getName() {
return name;
}

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

public TabCode()
{
super();
}

public TabCode(int code, String name) {
super();
this.code = code;
this.name = name;
}





}

接下来viewpager需要一个adapter:

/**
*
*/
package com.example.webservice.widget.ColumnHorizontalScrollView;

import java.util.List;

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.PagerAdapter;
import android.view.View;
import android.view.ViewGroup;

/**
* view pager adapter
*
* @author xhf
*
*/
public class ViewPagerAdapter extends FragmentPagerAdapter{

public ViewPagerAdapter(FragmentManager fm) {
super(fm);
// TODO Auto-generated constructor stub
}

private List mFragments;



public List getmFragments() {
return mFragments;
}


public void setmFragments(List mFragments) {
this.mFragments = mFragments;
}


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


@Override
public Fragment getItem(int arg0) {
// TODO Auto-generated method stub
return mFragments.get(arg0);
}

}


最后就是自己写的一个用来测试的fragment啦:

package com.example.webservice.widget.ColumnHorizontalScrollView;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;

import com.example.webservice.R;
/**
* 用来测试viewpager滑动的fragment
* @author xhf
*
*/
public class TabFragment extends Fragment {

private int index=0;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
Log.i("Test","TabFragment");
View view=inflater.inflate(R.layout.fragment_one_button, null);
return view;
}

@Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
Button btn=(Button)getView().findViewById(R.id.btnTest);
btn.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
((Button)v).setText(String.valueOf(index));
index++;
}
});
}


}



需要修改样式的,就自己修改其中相关的xml布局就好啦~


推荐阅读
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • Android开发实现的计时器功能示例
    本文分享了Android开发实现的计时器功能示例,包括效果图、布局和按钮的使用。通过使用Chronometer控件,可以实现计时器功能。该示例适用于Android平台,供开发者参考。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • ZSI.generate.Wsdl2PythonError: unsupported local simpleType restriction ... [详细]
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
  • Android系统源码分析Zygote和SystemServer启动过程详解
    本文详细解析了Android系统源码中Zygote和SystemServer的启动过程。首先介绍了系统framework层启动的内容,帮助理解四大组件的启动和管理过程。接着介绍了AMS、PMS等系统服务的作用和调用方式。然后详细分析了Zygote的启动过程,解释了Zygote在Android启动过程中的决定作用。最后通过时序图展示了整个过程。 ... [详细]
  • 本文介绍了RxJava在Android开发中的广泛应用以及其在事件总线(Event Bus)实现中的使用方法。RxJava是一种基于观察者模式的异步java库,可以提高开发效率、降低维护成本。通过RxJava,开发者可以实现事件的异步处理和链式操作。对于已经具备RxJava基础的开发者来说,本文将详细介绍如何利用RxJava实现事件总线,并提供了使用建议。 ... [详细]
  • 本文介绍了MVP架构模式及其在国庆技术博客中的应用。MVP架构模式是一种演变自MVC架构的新模式,其中View和Model之间的通信通过Presenter进行。相比MVC架构,MVP架构将交互逻辑放在Presenter内部,而View直接从Model中读取数据而不是通过Controller。本文还探讨了MVP架构在国庆技术博客中的具体应用。 ... [详细]
  • [翻译]PyCairo指南裁剪和masking
    裁剪和masking在PyCairo指南的这个部分,我么将讨论裁剪和masking操作。裁剪裁剪就是将图形的绘制限定在一定的区域内。这样做有一些效率的因素࿰ ... [详细]
  • 使用Flutternewintegration_test进行示例集成测试?回答首先在dev下的p ... [详细]
  • 注:根据Qt小神童的视频教程改编概论:利用最新的Qt5.1.1在windows下开发的一个小的时钟程序,有指针与表盘。1.Qtforwindows开发环境最新的Qt已经集 ... [详细]
  • 当我在doWork方法中运行代码时,通过单击button1,进度条按预期工作.但是,当我从其他方法(即btn2,btn3)将列表传递给doWork方法时,进度条在启动后会跳转到10 ... [详细]
author-avatar
林俊雯868043
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有