热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

Android拼图游戏玩转从基础到应用手势变化

这篇文章主要介绍了Android拼图游戏,教大家玩转从基础到应用手势变化,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

相信大家在小的时候都玩过拼图游戏,现如今,手机普及,能在手机上玩的游戏越来越多,于是乎,重温小时候,编写这个简易拼图游戏,而且也能进一步加深Android的一些基础知识。
老规矩,先是效果图:

这里我把为了演示效果,把图片打乱的很少,在代码里可以更改。

首先,有个默认的图片,可以用来拼图,也可以选择你喜欢的图片进行拼图,拼图的过程会记录移动的步数,并且当游戏胜利的时候会弹出一个笑脸提示,游戏胜利,用了多少步数。

ps:感兴趣的完全可以继续在这上面进行扩展,比如增加游戏难度的选项,可以将图片分成更多的小方块等等。

大体思路:将大图切割成各个小方块,用数组记录每个小方块的信息,用GridLayout来显示各个小方块,并且将某个小方块标记为空白方块(空白方块可以和相邻方块进行交换),在GridLayout上的各个小方块上增加点击事件和在整个屏幕上添加手势事件,每次点击或者有手势时,判断小方块是否能移动,最后在游戏胜利时弹出胜利提示。
话不多说,接下来,就是一步步实现拼图游戏的过程啦。

1.小方块相关的类。

这是小方块的各种变量的item,类,用来管理将大图切割成每个小方块的每个小方块的信息。很简单,就是各种变量和Setter和Getter方法直接上代码~

/**
 * Created by yyh on 2016/10/21.
 */
public class GameItemView{
  /**
   * 每个小方块的信息
   */
  //每个小方块的实际位置x,
  private int x=0;
  //每个小方块的实际位置y,
  private int y=0;
  //每个小方块的图片,
  private Bitmap bm;
  //每个小方块的图片位置x,
  private int p_x=0;
  //每个小方块的图片位置y.
  private int p_y=0;
  public GameItemView(int x, int y, Bitmap bm) {
    super();
    this.x = x;
    this.y = y;
    this.bm = bm;
    this.p_x=x;
    this.p_y=y;
  }
  public int getX() {
    return x;
  }
  public void setX(int x) {
    this.x = x;
  }
  public int getY() {
    return y;
  }

  public Bitmap getBm() {
    return bm;
  }

  public void setBm(Bitmap bm) {
    this.bm = bm;
  }

  public int getP_x() {
    return p_x;
  }

  public void setP_x(int p_x) {
    this.p_x = p_x;
  }

  public int getP_y() {
    return p_y;
  }

  public void setP_y(int p_y) {
    this.p_y = p_y;
  }
  /**
   * 判断每个小方块的位置是否正确
   * @return
   */
  public boolean isTrue(){
    if (x==p_x&&y==p_y){
      return true;
    }
    return false;
  }
}

2.主界面的布局

主界面很简单,一个Button,用来换图片,一个ImageView,用来显示原图,一个GridLayout用来进行拼图游戏,最后,一个TextView,用来显示完成这个拼图用了多少步数。布局如下:

<&#63;xml version="1.0" encoding="utf-8"&#63;>

  
    

3.打开图片选择图片

给Button设置点击事件,调用startActivityForResult(Intent intent,int requestCode);方法,来获取图片。

 bt_choice.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        Intent intent= new Intent("android.intent.action.GET_CONTENT");
        intent.setType("image/*");
        startActivityForResult(intent, CHOICE_PHOTO);//打开相册
      }
    });

在Activity中重写onActivityResult(int requestCode, int resultCode, Intent data)方法来显示选择的图片,以及初始化游戏。(图片选择完以后,就要进行图片的切割,和拼图游戏的开始。)

 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    switch (requestCode){
      case CHOICE_PHOTO:
        if (resultCode==RESULT_OK){
          //判断手机系统版本
          if (Build.VERSION.SDK_INT>=19){
            handleImageOnKitKat(data);
            //得到imageview中的图片
            BitmapDrawable bitmapDrawable= (BitmapDrawable) photo.getDrawable();
            bt_tupan=bitmapDrawable.getBitmap();
            //将原来GridLayout中的小方块移除,
            removeGameItem();
            //将新图切割成小方块并加入GridLayout.
            setGameItem();
            //开始游戏
            startGame();
          }else {
            handleImageBeforeKitKat(data);
            //得到imageview中的图片
            BitmapDrawable bitmapDrawable= (BitmapDrawable) photo.getDrawable();
            bt_tupan=bitmapDrawable.getBitmap();
             //将原来GridLayout中的小方块移除,
            removeGameItem();
            //将新图切割成小方块并加入GridLayout.
            setGameItem();
            //开始游戏
            startGame();
          }
        }
    }
  }

然后是选择图片的具体方法的实现函数。注释很清楚,不多说。我们的重点在拼图以及手势变化的具体实现,这里选择图片的方式很多。不多讲,网上有现成的框架。

 //手机不大于19的取数据方法
  private void handleImageBeforeKitKat(Intent data) {
    Uri uri =data.getData();
    String imagePath = getImagePath(uri, null);
    displayImage(imagePath);
  }
  /**
   * 手机大于19的取数据方法
   * @param data
   */
  @TargetApi(Build.VERSION_CODES.KITKAT)
  private void handleImageOnKitKat(Intent data) {
    String imagePath=null;
    Uri uri=data.getData();
    if (DocumentsContract.isDocumentUri(this,uri)){
      //如果是document类型的url,则通过document的id处理。
      String docId=DocumentsContract.getDocumentId(uri);
      if ("com.android.providers.media.documents".equals(uri.getAuthority())){
        String id =docId.split(":")[1];//解析出数字格式的id;
        String selection= MediaStore.Images.Media._ID+"="+id;
        imagePath=getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,selection);
      }else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())){
        Uri cOntenturi= ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"),Long.valueOf(docId));
        imagePath=getImagePath(contenturi,null);
      }
    }else if ("content".equalsIgnoreCase(uri.getScheme())){
      //如果不是document类型的uri,则使用普通的方式处理。
      imagePath=getImagePath(uri,null);
    }
    displayImage(imagePath);
  }
  /**
   * 显示图片
   * @param imagePath //图片的路径。
   */
  private void displayImage(String imagePath) {
    if (imagePath != null) {
      Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
      if (isHeigthBigWidth(bitmap)) {
        Bitmap bt = rotaingImageView(bitmap);//将图片旋转90度。
        Bitmap disbitmapt = ajustBitmap(bt);
        photo.setImageBitmap(disbitmapt);
      } else {
        Bitmap disbitmap = ajustBitmap(bitmap);
        photo.setImageBitmap(disbitmap);
      }
    }
  }

  /**
   * 调整图片的方向
   * @param bitmap
   * @return
   */
  private Bitmap rotaingImageView(Bitmap bitmap) {
    //旋转图片 动作
    Matrix matrix = new Matrix();;
    matrix.postRotate(270);
    // 创建新的图片
    Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0,
        bitmap.getWidth(), bitmap.getHeight(), matrix, true);
    return resizedBitmap;
  }
  /**
   * 得到图片的路径
   * @param externalContentUri
   * @param selection
   * @return
   */
  private String getImagePath(Uri externalContentUri, String selection) {
    String path=null;
    Cursor cursor=getContentResolver().query(externalContentUri, null, selection, null, null);
    if (cursor!=null){
      if (cursor.moveToFirst()){
        path=cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
      }
    }
    cursor.close();
    return path;
  }

4.拼图的各个小方块的形成过程。

看着各个小方块,我们用GridLayout来实现是最为方便的。所以,用一个GridLayout来显示大图切割后的各个小方块,用一个ImageView数组来保存各个小方块的信息,并且,我们默认把最后一个小方块设置为空白方块。

首先是各种需要的变量。注释很清楚。

 /**
   * 利用二维数组创建若干个游戏小方框
   */
  private ImageView [][] iv_game_arr=new ImageView[3][5];
  /**
   *游戏主界面
   *
   */
  private GridLayout gl_game_layout;
  //小方块的行和列
  private int i;
  private int j;
  /**空方块的全局变量*/
  private ImageView iv_null_imagview;

接着是从Imageview获取图片,并且将图片按照一定的行和列进行切割(这里将拼图设置为3行5列)。将切割后的各个小方块的信息保存在一个ImageView数组中。给每个小方块设置Tag,和点击监听。

 private void setGameItem() {
    //调整图片的尺寸
    Bitmap abitmap=ajustBitmap(bt_tupan);
    int ivWidth=getWindowManager().getDefaultDisplay().getWidth()/5;//每个游戏小方块的宽和高。切成正方形
    int tuWidth=abitmap.getWidth()/5; 
    for (int i=0;i

当然,我们选择的图片不可能都是符合标准的大小的,所以,在切割图片之前我们要对图片进行调整。将图片调整为5:3的比例。(这样切割成3行5列的小方块才能正确切割)这里对于width,我把每个小方块的间隔事先也算到里面去。

 //调整图片的大小
  private Bitmap ajustBitmap(Bitmap bitmap) {
    int width=getWindowManager().getDefaultDisplay().getWidth()-(iv_game_arr[0].length-1)*2;
    int heigth=width/5*3;
    Bitmap scaledBitmap=Bitmap.createScaledBitmap(bitmap, width, heigth, true);
    return scaledBitmap;
  }

将每个小方格放入到GridLayout中。

 /**
   * 将小方格放入GridLayout
   */
  private void startGame() {
    tv_step.setText("已用步数:0");
    for (i = 0; i 

5.小方块的点击事件和手势判断过程。

这里是拼图游戏的核心,弄懂了小方块的移动变化规律,也就弄懂了拼图游戏。

对于点击事件,首先拿到被点击的小方块的各种信息(位置、图案)和空白小方块的位置信息,判断被点击的小方块是否和空白小方块相邻,如果相邻,就移动交换数据(用TranslateAnimation来实现移动动画),如果不相邻则无操作。
a.判断点击方块和空白方块是否相邻的方法

/**
   *  判断当前点击的方块,是否和空方块相邻。
   * @param imageView 当前点击的方块
   * @return true:相邻。 false:不相邻。
   */
  public boolean isAdjacentNullImageView(ImageView imageView){
    //获取当前空方块的位置与点击方块的位置
    GameItemView null_gameItemView= (GameItemView) iv_null_imagview.getTag();
    GameItemView now_gameItem_view = (GameItemView) imageView.getTag();
   if(null_gameItemView.getY()==now_gameItem_view.getY()&&now_gameItem_view.getX()+1==null_gameItemView.getX()){//当前点击的方块在空方块的上面
      return true;
    }else if(null_gameItemView.getY()==now_gameItem_view.getY()&&now_gameItem_view.getX()==null_gameItemView.getX()+1){//当前点击的方块在空方块的下面
      return true;
    }else if(null_gameItemView.getY()==now_gameItem_view.getY()+1&&now_gameItem_view.getX()==null_gameItemView.getX()){//当前点击的方块在空方块的左面
      return true;
    }else if(null_gameItemView.getY()+1==now_gameItem_view.getY()&&now_gameItem_view.getX()==null_gameItemView.getX()){ ////当前点击的方块在空方块的右面
      return true;
    }
    return false;
  }

b.接着是如果相邻就进入方块数据交换的方法
这里有个方法重载,是否需要动画效果,没有动画效果的数据交换是为初始化游戏时打乱拼图做准备的。这里将核心交换代码列出。每次交换后还要判断是否游戏胜利(即是否拼图完成~)。

    //得到点击方块绑定的数据
      GameItemView gameItemView = (GameItemView) itemimageView.getTag();
      //将空方块的图案设置为点击方块
      iv_null_imagview.setImageBitmap(gameItemView.getBm());
      //得到空方块绑定的数据
      GameItemView null_gameItemView = (GameItemView) iv_null_imagview.getTag();
      //交换数据(将点击方块的数据传入空方块)
      null_gameItemView.setBm(gameItemView.getBm());
      null_gameItemView.setP_x(gameItemView.getP_x());
      null_gameItemView.setP_y(gameItemView.getP_y());
      //设置当前点击的方块为空方块。
      setNullImageView(itemimageView);
      if (isStart){
        isGameWin();//成功时,会弹一个吐司。
      }

c.交换时的动画设置
交换设置动画时,首先判断移动的方向,根据方向设置不同的移动动画,然后再监听动画完成后,进行数据交换操作。即上面b.接着是如果相邻就进入方块数据交换的方法.最后执行动画。

 //1.创建一个动画,设置方向,移动的距离
//判断方向,设置动画
    if (itemimageView.getX()>iv_null_imagview.getX()){//当前点击的方块在空方块的上面
      //下移
      translateAnimation = new TranslateAnimation(0.1f,-itemimageView.getWidth(),0.1f,0.1f);
    }else if (itemimageView.getX()iv_null_imagview.getY()){//当前点击的方块在空方块的左面
      //右移
      translateAnimation=new TranslateAnimation(0.1f,0.1f,0.1f,-itemimageView.getWidth());
    }else if(itemimageView.getY()

点击事件的流程就完了,接下来是手势判断的事件。即不仅可以通过点击小方块进行移动,也可以通过手势移动小方块。

One.创建手势对象
在onFling方法中完成手势相关的操作。

 //创建手势对象
    gestureDetector =new GestureDetector(this, new GestureDetector.OnGestureListener() {
      @Override
      public boolean onDown(MotionEvent e) {
        return false;
      }
      @Override
      public void onShowPress(MotionEvent e) {
      }
      @Override
      public boolean onSingleTapUp(MotionEvent e) {
        return false;
      }
      @Override
      public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        return false;
      }
      @Override
      public void onLongPress(MotionEvent e) {
      }
      @Override
      public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
      //手势相关的操作
      ......
  }

接着我们onFling方法中做具体操作

Two.判断手势移动的方向
根据返回值的不同得到不同的移动方向。

 /**
   * 增加手势滑动,根据手势判断是上下左右滑动
   * @param start_x 手势起始点x
   * @param start_y 手势起始点y
   * @param end_x 手势终止点 x
   * @param end_y 手势终止点y
   * @return 1:上 2:下 3:左 4:右
   */
  public int getDirctionByGesure(float start_x,float start_y,float end_x,float end_y){
    boolean isLeftOrRight =(Math.abs(end_x-start_x)>Math.abs(end_y-start_y))&#63;true:false; //是否是左右
    if(isLeftOrRight){//左右
      boolean isLeft=(end_x-start_x)>0&#63;false:true;
      if(isLeft){
        return 3;
      }else {
        return 4;
      }
    }else{//上下
      boolean isUp=(end_y-start_y)>0&#63;false:true;
      if (isUp){
        return 1;
      }else {
        return 2;
      }
    }
  }

Three.根据空方块和移动的方向,判断能否移动以及进行移动操作。
因为是手势,移动的肯定是空方块周围的方块,所以重点就是要判断空方块在要移动的方块的那个方向,再根据方向判断能否移动,进行移动操作。(其中changeDateByImageView()中的方法就是具体的方块交换数据及移动的操作。就是点击事件的那个方法。)

/**重载changeByDirGes(int type)方法;
   * 根据手势的方向,对空方块相邻位置的方块进行移动。
   * @param type 方向的返回值 1:上 2:下 3:左 5:右
   * @param isAnim 是否有动画 true:有动画,false:无动画
   */
  public void changeByDirGes(int type,boolean isAnim){
    //1.获取当前空方块的位置。
    GameItemView null_gameItemView= (GameItemView) iv_null_imagview.getTag();
    int new_x=null_gameItemView.getX();
    int new_y=null_gameItemView.getY();
    //2.根据方向,设置相应相邻的位置坐标。
    if (type==1){//说明空方块在要移动的方块的上面。
      new_x++;
    }else if (type==2){//空方块在要移动的方块的下面
      new_x--;
    }else if (type==3){//空方块在要移动的方块的左面
      new_y++;
    }else if (type==4){//空方块在要移动的方块的右面
      new_y--;
    }
    //3.判断这个新坐标是否存在
    if(new_x>=0&&new_x=0&&new_y

好了,手势事件也就大功告成了~

当然这里有两个要注意的地方。1.首先要对当前的Activity设置onTouchEvent()方法,将onTouch事件交由手势去处理,其次也要设置dispatchTouchEvent()方法,在里面也要向下分发给手势事件,如果不设置向下分发给手势判断,那么在GridLayout里,就只能触发点击事件而手势事件就不会起作用了。2.要增加一个是否在移动过程中的flag,如果在移动过程中,就什么也不做,要不然每次点击小方块即使在移动过程中,也会触发点击事件从而又进行动画移动,造成不好的用户体验。

 @Override
  public boolean onTouchEvent(MotionEvent event) {
    return gestureDetector.onTouchEvent(event);
  }
  @Override
  public boolean dispatchTouchEvent(MotionEvent ev) {
    gestureDetector.onTouchEvent(ev);
    return super.dispatchTouchEvent(ev);
  }

6.游戏开始打乱方块以及游戏结束时弹出Toast提示的方法。

代码很简单,直接上代码,其中,弹出的Toast是一个带有自定义View动画的Toast.

 //随机打乱图片的顺序
  public void randomOrder(){
    //打乱的次数,为了测试方便,设置很小。
    for (int i=0;i<5;i++){
      //根据手势,交换数据,无动画。
      int type = (int) (Math.random()*4)+1;
      // Log.i("sssssssssfdfdfd","交换次数"+i+"type的值"+type);
      changeByDirGes(type, false);
    }
  }
  /**
   * 判断游戏结束的方法
   */
  public void isGameWin(){
    //游戏胜利标志
    boolean isGameWin =true;
    //遍历每个小方块
    for (i = 0; i 

好了,重要的部分都已经完了,这里还有个自定义View的Toast,关于Toast的详解,将在下篇文章,这里先简单说明下自定义Toast的实现过程。
首先,新建一个SuccessToast类,(笑脸包括左眼,有眼,笑脸弧)。我们将核心的过程给出。利用动画,实现动态笑脸画制过程。

 @Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    mPaint.setStyle(Paint.Style.STROKE);
    //话笑脸弧
    canvas.drawArc(rectF, 180, endAngle, false, mPaint);
    mPaint.setStyle(Paint.Style.FILL);
    if (isSmileLeft) {
    //如果是左眼,画左眼
      canvas.drawCircle(mPadding + mEyeWidth + mEyeWidth / 2, mWidth / 3, mEyeWidth, mPaint);
    }
    if (isSmileRight) {
    //如果是有眼,画右眼。
      canvas.drawCircle(mWidth - mPadding - mEyeWidth - mEyeWidth / 2, mWidth / 3, mEyeWidth, mPaint);
    }
  }

 /**
   * 开始动画的方法
   * @param startF 起始值
   * @param endF  结束值
   * @param time 动画的时间
   * @return
   */
  private ValueAnimator startViewAnim(float startF, final float endF, long time) {
    //设置valueAnimator 的起始值和结束值。
    valueAnimator = ValueAnimator.ofFloat(startF, endF);
    //设置动画时间
    valueAnimator.setDuration(time);
    //设置补间器。控制动画的变化速率
    valueAnimator.setInterpolator(new LinearInterpolator());
    //设置监听器。监听动画值的变化,做出相应方式。
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
      @Override
      public void onAnimationUpdate(ValueAnimator valueAnimator) {

        mAnimatedValue = (float) valueAnimator.getAnimatedValue();
        //如果value的值小于0.5
        if (mAnimatedValue <0.5) {
          isSmileLeft = false;
          isSmileRight = false;
          endAngle = -360 * (mAnimatedValue);
          //如果value的值在0.55和0.7之间
        } else if (mAnimatedValue > 0.55 && mAnimatedValue <0.7) {
          endAngle = -180;
          isSmileLeft = true;
          isSmileRight = false;
          //其他
        } else {
          endAngle = -180;
          isSmileLeft = true;
          isSmileRight = true;
        }
        //重绘
        postInvalidate();
      }
    });

    if (!valueAnimator.isRunning()) {
      valueAnimator.start();
    }
    return valueAnimator;
  }

然后新建一个success_toast_layout.xml,完成toast的布局。布局是左右(左边笑脸view,右边TextView的提示。)

<&#63;xml version="1.0" encoding="utf-8"&#63;>

  
    
      
    
    
  


最后新建一个ToastUtil类,管理自定义的Toast.

/**
 * Created by yyh on 2016/10/25.
 */
public class ToastUtil {
  public static final int LENGTH_SHORT = 0;
  public static final int LENGTH_LOnG= 1;

  public static final int SUCCESS = 1;


  static SuccessToast successToastView;


  public static void makeText(Context context, String msg, int length, int type) {
    Toast toast = new Toast(context);
    switch (type) {
      case 1: {
        View layout = LayoutInflater.from(context).inflate(R.layout.success_toast_layout, null, false);
        TextView text = (TextView) layout.findViewById(R.id.toastMessage);
        text.setText(msg);
        successToastView = (SuccessToast) layout.findViewById(R.id.successView);
        successToastView.startAnim();
        text.setBackgroundResource(R.drawable.success_toast);
        text.setTextColor(Color.parseColor("#FFFFFF"));
        toast.setView(layout);
        break;
      }

    }
    toast.setDuration(length);
    toast.show();
  }

}

这样就可以在ManiActivity中调用这个自定义Toast了。
好了,完结。

游戏源码:拼图游戏的实现过程
gitHub:拼图游戏。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • RecyclerView初步学习(一)
    RecyclerView初步学习(一)ReCyclerView提供了一种插件式的编程模式,除了提供ViewHolder缓存模式,还可以自定义动画,分割符,布局样式,相比于传统的ListVi ... [详细]
  • Android LED 数字字体的应用与实现
    本文介绍了一种适用于 Android 应用的 LED 数字字体(digital font),并详细描述了其在 UI 设计中的应用场景及其实现方法。这种字体常用于视频、广告倒计时等场景,能够增强视觉效果。 ... [详细]
  • Android 九宫格布局详解及实现:人人网应用示例
    本文深入探讨了人人网Android应用中独特的九宫格布局设计,解析其背后的GridView实现原理,并提供详细的代码示例。这种布局方式不仅美观大方,而且在现代Android应用中较为少见,值得开发者借鉴。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • 解决微信电脑版无法刷朋友圈问题:使用安卓远程投屏方案
    在工作期间想要浏览微信和朋友圈却不太方便?虽然微信电脑版目前不支持直接刷朋友圈,但通过远程投屏技术,可以轻松实现在电脑上操作安卓设备的功能。 ... [详细]
  • 本文详细介绍了 Java 中 org.apache.xmlbeans.SchemaType 类的 getBaseEnumType() 方法,提供了多个代码示例,并解释了其在不同场景下的使用方法。 ... [详细]
  • 本文深入探讨了 com.example.android.sunshine.data.TestUtilities 中 validateThenCloseCursor() 方法的使用方法及其代码示例,旨在帮助开发者更好地理解和应用该方法。 ... [详细]
  • CSS 布局:液态三栏混合宽度布局
    本文介绍了如何使用 CSS 实现液态的三栏布局,其中各栏具有不同的宽度设置。通过调整容器和内容区域的属性,可以实现灵活且响应式的网页设计。 ... [详细]
  • 数据库内核开发入门 | 搭建研发环境的初步指南
    本课程将带你从零开始,逐步掌握数据库内核开发的基础知识和实践技能,重点介绍如何搭建OceanBase的开发环境。 ... [详细]
  • 本文详细介绍了如何使用 Yii2 的 GridView 组件在列表页面实现数据的直接编辑功能。通过具体的代码示例和步骤,帮助开发者快速掌握这一实用技巧。 ... [详细]
  • 本文详细介绍了Java中org.eclipse.ui.forms.widgets.ExpandableComposite类的addExpansionListener()方法,并提供了多个实际代码示例,帮助开发者更好地理解和使用该方法。这些示例来源于多个知名开源项目,具有很高的参考价值。 ... [详细]
  • 本文介绍如何使用 Sortable.js 库实现元素的拖拽和位置交换功能。Sortable.js 是一个轻量级、无依赖的 JavaScript 库,支持拖拽排序、动画效果和多种插件扩展。通过简单的配置和事件处理,可以轻松实现复杂的功能。 ... [详细]
  • 探讨一个显示数字的故障计算器,它支持两种操作:将当前数字乘以2或减去1。本文将详细介绍如何用最少的操作次数将初始值X转换为目标值Y。 ... [详细]
  • 扫描线三巨头 hdu1928hdu 1255  hdu 1542 [POJ 1151]
    学习链接:http:blog.csdn.netlwt36articledetails48908031学习扫描线主要学习的是一种扫描的思想,后期可以求解很 ... [详细]
author-avatar
Caroline19921009
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有