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

实现一个轮播控件并封装起来

作者:夏至,欢迎转载,但请保留这段申明,谢谢http:blog.csdn.netu011418943articledetails77370490需求,在首页开发中,我们经常会使用轮

作者: 夏至,欢迎转载,但请保留这段申明,谢谢
http://blog.csdn.net/u011418943/article/details/77370490

需求,在首页开发中,我们经常会使用轮播图片的方法,来达到广告栏的效果,而它的实现方式呢,而比较简单,就是一个 viewpager ,然后让它循环起来就可以了。

而它的编写是比较繁琐的,因为除了图片和文字说明外,还需要底部的圆点指示器(你可以写成其他相撞),所以,封装起来,还是可以省很多事情的。

当然,github 有一大堆 轮子可以使用,但为何不自己也搞一个呢?

首先看一下今天要实现的效果:

《实现一个轮播控件并封装起来》 这里写图片描述

首先,先看一下普通方式应该怎么实现。

布局文件:


xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_
android:layout_
android:orientation="vertical"
android:clipChildren="false"
android:clipToPadding="false"
android:background="#22e12222"
tools:cOntext="com.rachel.activitytest.MainActivity">
android:layout_marginTop="20dp"
android:id="@+id/viewpager"
android:layout_
android:layout_
android:clipChildren="false"
android:clipToPadding="false"
/>

这里就不讲 viewpager 的配置什么的了,因为讲了估计你也不想看,这里讲讲轮播的实现把。

1、首尾填充实现循环

什么意思呢 ? 就是假如我们要轮播的是 三张图片,那么实际上,填充的是 五张 图片,如下面这张图:

《实现一个轮播控件并封装起来》 这里写图片描述

即在初始化的时候,1 的前面,填充3,3,的后面填充1,然后再用 viewpager.setCurrentItem(),不动声色的直接设置过去,达到一个移花接木的效果,这样看起来就实现了轮播的效果了。
所以,数据的初始化,如下面所示:

private List initImg() {
for (int i = 0; i View view = LayoutInflater.from(this).inflate(R.layout.viewpager_item,null);
ImageView imageView = (ImageView) view.findViewById(R.id.viewpager_item_img);
if (i == 0){ //第一张的时候,把最后一张填充到第一张的前一张
imageView.setImageResource(images[images.length - 1]);
}else if (i == images.length + 1){
imageView.setImageResource(images[0]);
}else {
imageView.setImageResource(images[i - 1]);
}
mViews.add(view);
mViews2.add(view);
}
return mViews;
}

数据初始化之后,我们还需要在滑动的时候,不动声色的 切换,这样才能有一个轮播的效果,所以,切换的代码如下:

mViewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
}
@Override
public void onPageScrollStateChanged(int state) {
if (state == ViewPager.SCROLL_STATE_IDLE){
int currentpageid = mViewpager.getCurrentItem();
if (currentpageid == 0){
mViewpager.setCurrentItem(images.length,false);
} else if (currentpageid == (images.length +1)){
mViewpager.setCurrentItem(1,false);
}
}
}
});

完整代码如下:

public class MainActivity extends AppCompatActivity {
private static final String TAG = "zsr";
//展示三张,其实是有五张
int[] images = new int[]{R.mipmap.beauty,R.mipmap.beuty1,R.mipmap.beauty2};
private ViewPager mViewpager;
private List mViews = new ArrayList<>();
private List mViews2 = new ArrayList<>();
private int lastPage;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mViewpager = (ViewPager) findViewById(R.id.viewpager);
initImg();
mViewpager.setAdapter(new CusTomAdapter());
// mViewpager.setPageTransformer(false,new customTransFromer());
mViewpager.setOffscreenPageLimit(3);
mViewpager.setCurrentItem((images.length + 2)/2); //取中间的位置
mViewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
}
@Override
public void onPageScrollStateChanged(int state) {
if (state == ViewPager.SCROLL_STATE_IDLE){
int currentpageid = mViewpager.getCurrentItem();
if (currentpageid == 0){
mViewpager.setCurrentItem(images.length,false);
} else if (currentpageid == (images.length +1)){
mViewpager.setCurrentItem(1,false);
}
}
}
});
}
class CusTomAdapter extends PagerAdapter{
@Override
public int getCount() {
return mViews.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
//return super.instantiateItem(container, position);
container.addView(mViews.get(position));
return mViews.get(position);
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView(mViews.get(position));
}
}
private List initImg() {
for (int i = 0; i View view = LayoutInflater.from(this).inflate(R.layout.viewpager_item,null);
ImageView imageView = (ImageView) view.findViewById(R.id.viewpager_item_img);
if (i == 0){ //第一张的时候,把最后一张填充到第一张的前一张
imageView.setImageResource(images[images.length - 1]);
}else if (i == images.length + 1){
imageView.setImageResource(images[0]);
}else {
imageView.setImageResource(images[i - 1]);
}
mViews.add(view);
mViews2.add(view);
}
return mViews;
}
}

效果呢,如下所示:

《实现一个轮播控件并封装起来》

但这种方式,在快速滚动的时候,不是很利索,原因就是切换那里,我们是在滚动结束的时候在 切过去的,如果你在快速滚动,就有一种最后一张切到第一张,有卡顿的感觉。

2、getCount 中返回一个很大的数字,实现轮播

这种方式,就是在 pagerveiw 的 getCount 中,返回一个很大的数字,如下:

@Override
public int getCount() {
//设置一个很大的数,用来实现轮播效果,实际上可以不用这么大
return Integer.MAX_VALUE;
}

为了在 adapter 中获取到正确的值,把 position 取余即可。然后为了方便左右都能滑动,在初始化的时候,把 setcurrentitem 的值设置成中间即可。为了方便,这里新建一个类,继承 Viewpager:

public class BannerViewPager extends ViewPager {
private static final String TAG = "BannerViewPager";
private BannerCustomAdapter mBannerCustomAdapter;
public BannerViewPager(Context context) {
super(context);
}
public BannerViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setAdapter(List views) {
setAdapter(new BannerViewAdapter(views));
}
class BannerViewAdapter extends PagerAdapter{
List views;
public BannerViewAdapter(List views) {
this.views = views;
}
@Override
public int getCount() {
//设置一个很大的数,用来实现轮播效果
return Integer.MAX_VALUE;
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
//自己适配类型,比如imageview
View view = null;
if (this.views != null){
//对Viewpager页号求模去除View列表中要显示的项
position %= this.views.size();

//如果View已经在之前添加到了一个父组件,则必须先remove,否则会抛出IllegalStateException。
view = this.views.get(position);
ViewParent viewParent = view.getParent();
if (viewParent!=null){
parent.removeAllView(view);
}
}
container.addView(view);
return view;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
//上面已经对 item remove了,这里如果再次remove,则实现不出来
// container.removeView(this.views.get(position % this.views.size()));

}
}
}

然后,替换一下xml文件:


xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_
android:layout_
android:orientation="vertical"
android:clipChildren="false"
android:clipToPadding="false"
android:background="#22e12222"
tools:cOntext="com.rachel.activitytest.MainActivity">
android:layout_marginTop="20dp"
android:id="@+id/custom_viewpager"
android:layout_
android:layout_/>

主函数这样写:

public class MainActivity extends AppCompatActivity {
private static final String TAG = "zsr";
//展示三张,其实是有五张
int[] images = new int[]{R.mipmap.beauty,R.mipmap.beuty1,R.mipmap.beauty2};
private ViewPager mViewpager;
private List mViews = new ArrayList<>();
private int lastPage;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initImg();
BannerViewPager bannerViewPager = (BannerViewPager) findViewById(R.id.custom_viewpager);
bannerViewPager.setAdapter(mViews);
bannerViewPager.setPageTransformer(false,new customTransFromer());
bannerViewPager.setCurrentItem(900); //取中间或者大一点的数都可以,保证左边有item
}
private List initImg() {
for (int i = 0; i View view = LayoutInflater.from(this).inflate(R.layout.viewpager_item,null);
ImageView imageView = (ImageView) view.findViewById(R.id.viewpager_item_img);
mViews.add(view);
}
return mViews;
}
}

这样也实现了上面一样的效果。

当然,你可以加写 viewpager 的动画,比如魅族的 bannerview:

/**
* 魅族效果
*/
class ZoomOutPageTransformer implements ViewPager.PageTransformer {
private static final float MAX_SCALE = 1.0f;
private static final float MIN_SCALE = 0.9f;//0.85f
@Override
public void transformPage(View view, float position) {
//setScaleY只支持api11以上
if (position <-1) {
// view.setScaleX(MIN_SCALE);
view.setScaleY(MIN_SCALE);
} else if (position <= 1) //a页滑动至b页 ; a页从 0.0 -1 ;b页从1 ~ 0.0
{ // [-1,1]
// Log.e("TAG", view + " , " + position + "");
float scaleFactor = MIN_SCALE + (1 - Math.abs(position)) * (MAX_SCALE - MIN_SCALE);
// view.setScaleX(scaleFactor);
//每次滑动后进行微小的移动目的是为了防止在三星的某些手机上出现两边的页面为显示的情况
view.setScaleY(scaleFactor);
} else { // (1,+Infinity]
// view.setScaleX(MIN_SCALE);
view.setScaleY(MIN_SCALE);
}
}
}

在 viewpager 设置一下:

mViewpager.setPageTransformer(false,new ZoomOutPageTransformer());

当然,你需要在 xml中,设置一个 viewpager 左右的margin 和在根布局中添加 clipChildren = false:


xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_
android:layout_
android:orientation="vertical"
android:clipChildren="false"
android:clipToPadding="false"
android:background="#22e12222"
tools:cOntext="com.rachel.activitytest.MainActivity">
android:layout_marginTop="20dp"
android:id="@+id/viewpager"
android:layout_
android:layout_
android:clipChildren="false"
android:clipToPadding="false"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
/>

效果如下:

《实现一个轮播控件并封装起来》

轮播与封装

这个就比较简单了,用一个 Handle 就可以了,需要注意的是,在按下的时候,需要取消消息,在抬起之后再取恢复;而上面的这种做法,其实还是有点问题的,用户除了要配置数据之外,还有额外的 viewpager 的配置,还有底部小圆圈的配置,这样是需要配置天多,那能不能我们先封装起来,用户再用的时候,只要配置数据就可以了?
当然可以,这里我们新建一个 xml,包含 viewpager 和 底部导航圆点 banner_layout.xml:


android:layout_
android:layout_
android:clipChildren="false"
>
android:id="@+id/banner_viewpager"
android:layout_
android:layout_
/>
android:id="@+id/banner_indeticor"
android:layout_
android:layout_
android:layout_alignParentBottom="true"
android:orientation="horizontal"
android:gravity="center"
android:layout_marginBottom="10dp"
/>

接着新建一个类,让它继承 releativelayout,然后把这个 banner_layout.xml ,加进来即可:

public class CusViewPager extends RelativeLayout implements ViewPager.OnPageChangeListener, View.OnTouchListener {
private ViewPager mViewPager;
private Context mContext;
private LinearLayout mLinearLayout; public CusViewPager(Context context) {
this(context,null);
}
public CusViewPager(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public CusViewPager(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mCOntext= context;
View view = LayoutInflater.from(context).inflate(R.layout.banner_layout,null);
addView(view); // 把包含 viewpager 和 底部 linearlayout的view 加给自身
mViewPager = (ViewPager) view.findViewById(R.id.banner_viewpager);
mLinearLayout = (LinearLayout) view.findViewById(R.id.banner_indeticor);
mViewPager.setOnTouchListener(this);
}
....
}

这样,我们在这里就可以操作 viewpager 和 底部小圆点的操作了。关于底部小圆点的,可以参考我的另一篇文章:
5分钟搞定开机引导界面

完整代码如下:

public class CusViewPager extends RelativeLayout implements ViewPager.OnPageChangeListener, View.OnTouchListener {
private static final String TAG = "zsr";
private ViewPager mViewPager;
private Context mContext;
private LinearLayout mLinearLayout;
private static final int LOOP_COUNT = 5000;
private static final int LOOP_START = 1;
private static final int LOOP_TIME = 1000;
private int mCurrentPageId;
private List mPointLists = new ArrayList<>();
public CusViewPager(Context context) {
this(context,null);
}
public CusViewPager(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public CusViewPager(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mCOntext= context;
View view = LayoutInflater.from(context).inflate(R.layout.banner_layout,null);
addView(view);
mViewPager = (ViewPager) view.findViewById(R.id.banner_viewpager);
mLinearLayout = (LinearLayout) view.findViewById(R.id.banner_indeticor);
mViewPager.setOnTouchListener(this);
}
Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case LOOP_START:
//这里重新获取一下 id,防止手动滑动而导致位置错乱
mCurrentPageId = mViewPager.getCurrentItem();
if (mCurrentPageId > LOOP_COUNT /2 ){
mViewPager.setCurrentItem(++mCurrentPageId);
}
if (mCurrentPageId > LOOP_COUNT){
mCurrentPageId = LOOP_COUNT+1;
}
mHandler.sendEmptyMessageDelayed(LOOP_START,LOOP_COUNT);
break;
}
}
};
public void setDatas(List lists){
if (mViewPager != null) {
mViewPager.setAdapter(new AutoAdapter(lists));
mViewPager.setCurrentItem(lists.size()+LOOP_COUNT/2);
mCurrentPageId = lists.size()+LOOP_COUNT/2;
initPoint(lists);
mViewPager.addOnPageChangeListener(this);
// setViewScrollTime(mContext,mViewPager,300);
mHandler.sendEmptyMessageDelayed(LOOP_START,LOOP_TIME);
Log.d(TAG, "handleMessage: "+System.currentTimeMillis());
}
}
private void initPoint(List lists) {
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
params.setMargins(15,0,0,0);
for (int i = 0; i ImageView imageView = new ImageView(mContext);
imageView.setImageResource(R.drawable.pointselector);
imageView.setLayoutParams(params);
if (i == 0){
imageView.setSelected(true);
}else{
imageView.setSelected(false);
}
mPointLists.add(imageView);
mLinearLayout.addView(imageView);

}
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
for (int i = 0; i View view = mPointLists.get(i);
if (i == (position % mPointLists.size())){
view.setSelected(true);
}else{
view.setSelected(false);
}
}
}
@Override
public void onPageScrollStateChanged(int state) {
}
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
mHandler.removeMessages(LOOP_START);
break;
case MotionEvent.ACTION_UP:
//手指抬起3s后,仍没有再次按下,则启动轮播
mHandler.sendEmptyMessageDelayed(LOOP_START,3000);
break;
}
return false;
}
class AutoAdapter extends PagerAdapter {
List datas;
public AutoAdapter(List datas) {
this.datas = datas;
}
@Override
public int getCount() {
return datas.size() + LOOP_COUNT;
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
View view = datas.get(position % datas.size());
//Log.d(TAG, "instantiateItem: "+view);
ViewGroup parent = (ViewGroup) view.getParent();
if (parent != null) {
parent.removeAllViews();
}
container.addView(view);
return view;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
}
/**
* 魅族效果
*/
class ZoomOutPageTransformer implements ViewPager.PageTransformer {
private static final float MAX_SCALE = 1.0f;
private static final float MIN_SCALE = 0.9f;//0.85f
@Override
public void transformPage(View view, float position) {
//setScaleY只支持api11以上
if (position <-1) {
// view.setScaleX(MIN_SCALE);
view.setScaleY(MIN_SCALE);
} else if (position <= 1) //a页滑动至b页 ; a页从 0.0 -1 ;b页从1 ~ 0.0
{ // [-1,1]
// Log.e("TAG", view + " , " + position + "");
float scaleFactor = MIN_SCALE + (1 - Math.abs(position)) * (MAX_SCALE - MIN_SCALE);
// view.setScaleX(scaleFactor);
//每次滑动后进行微小的移动目的是为了防止在三星的某些手机上出现两边的页面为显示的情况
view.setScaleY(scaleFactor);
} else { // (1,+Infinity]
// view.setScaleX(MIN_SCALE);
view.setScaleY(MIN_SCALE);
}
}
}
/**
* 渐隐效果
*/
class DepthPageTransformer implements ViewPager.PageTransformer {
private static final float MIN_SCALE = 0.75f;
public void transformPage(View view, float position) {
int pageWidth = view.getWidth();
if (position <-1) { // [-Infinity,-1)
// This page is way off-screen to the left.
view.setAlpha(0);
} else if (position <= 0) { // [-1,0]
// Use the default slide transition when moving to the left page
view.setAlpha(1);
view.setTranslationX(0);
view.setScaleX(1);
view.setScaleY(1);
} else if (position <= 1) { // (0,1]
// Fade the page out.
view.setAlpha(1 - position);
// Counteract the default slide transition
view.setTranslationX(pageWidth * -position);
// Scale the page down (between MIN_SCALE and 1)
float scaleFactor = MIN_SCALE
+ (1 - MIN_SCALE) * (1 - Math.abs(position));
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0);
}
}
}
private void setViewScrollTime(Context context,ViewPager viewpager,int time){
FixedSpeedScroller mScroller = null;
try {
Field mField;
mField = ViewPager.class.getDeclaredField("mScroller");
mField.setAccessible(true);
mScroller = new FixedSpeedScroller(context,
new AccelerateInterpolator());
mScroller.setmDuration(time);
mField.set(viewpager, mScroller);
} catch (Exception e) {
e.printStackTrace();
}
}
}

所以,在使用的时候,我们只要加载布局:

android:id="@+id/autoview"
android:layout_
android:layout_/>

在主函数中调用即可:

CusViewPager autoView = (CusViewPager) view.findViewById(R.id.autoview);
autoView.setDatas(mDatas);

这样就省去了很多的步骤了。效果如下:

《实现一个轮播控件并封装起来》 这里写图片描述


推荐阅读
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • baresip android编译、运行教程1语音通话
    本文介绍了如何在安卓平台上编译和运行baresip android,包括下载相关的sdk和ndk,修改ndk路径和输出目录,以及创建一个c++的安卓工程并将目录考到cpp下。详细步骤可参考给出的链接和文档。 ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • 在Docker中,将主机目录挂载到容器中作为volume使用时,常常会遇到文件权限问题。这是因为容器内外的UID不同所导致的。本文介绍了解决这个问题的方法,包括使用gosu和suexec工具以及在Dockerfile中配置volume的权限。通过这些方法,可以避免在使用Docker时出现无写权限的情况。 ... [详细]
  • 本文讲述了如何通过代码在Android中更改Recycler视图项的背景颜色。通过在onBindViewHolder方法中设置条件判断,可以实现根据条件改变背景颜色的效果。同时,还介绍了如何修改底部边框颜色以及提供了RecyclerView Fragment layout.xml和项目布局文件的示例代码。 ... [详细]
  • Android Studio Bumblebee | 2021.1.1(大黄蜂版本使用介绍)
    本文介绍了Android Studio Bumblebee | 2021.1.1(大黄蜂版本)的使用方法和相关知识,包括Gradle的介绍、设备管理器的配置、无线调试、新版本问题等内容。同时还提供了更新版本的下载地址和启动页面截图。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 解决Cydia数据库错误:could not open file /var/lib/dpkg/status 的方法
    本文介绍了解决iOS系统中Cydia数据库错误的方法。通过使用苹果电脑上的Impactor工具和NewTerm软件,以及ifunbox工具和终端命令,可以解决该问题。具体步骤包括下载所需工具、连接手机到电脑、安装NewTerm、下载ifunbox并注册Dropbox账号、下载并解压lib.zip文件、将lib文件夹拖入Books文件夹中,并将lib文件夹拷贝到/var/目录下。以上方法适用于已经越狱且出现Cydia数据库错误的iPhone手机。 ... [详细]
  • 拥抱Android Design Support Library新变化(导航视图、悬浮ActionBar)
    转载请注明明桑AndroidAndroid5.0Loollipop作为Android最重要的版本之一,为我们带来了全新的界面风格和设计语言。看起来很受欢迎࿰ ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • MyBatis多表查询与动态SQL使用
    本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]
  • IjustinheritedsomewebpageswhichusesMooTools.IneverusedMooTools.NowIneedtoaddsomef ... [详细]
author-avatar
Y死一般的痛过
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有