主頁 > 前端設計 > View體系詳解

View體系詳解

2020-09-29 04:32:24 前端設計

一、學習腦圖

二、View基礎

2.1 什么是View

Q1:怎么理解View

  • View是界面層的控制元件的一種抽象,代表了一個控制元件,
  • android在視覺上的呈現,
  • 是所有控制元件是基類,可以是單個控制元件View可以是一組控制元件ViewGroup

Q2:View的重要性?

ViewAndroid中是一個十分重要的概念,雖然說View不屬于四大組件,但是它的作用堪比四大組件,在開發中,Activity承擔了可視化的功能,Android提供了很多基礎的控制元件,當我們不滿足于這些基礎控制元件的功能時,可以用自定義控制元件,而控制元件的自定義就需要對View體系有深入的了解,

2.2 View的位置引數

Android系統中,有兩種坐標系,分別是Android坐標系和View坐標系,

2.2.1 Android坐標系
  • 將螢屏左上角作為坐標原點
  • 原點向右是X軸正方向
  • 原點向下是Y軸正方向

注意:使用getRawX()getRawY()方法獲得的坐標是Android坐標系的坐標

2.2.2 View坐標系

Q1:View的位置由什么來決定?

四個頂點:top(左上角縱坐標)、left(左上角橫坐標)、right(右下角橫坐標)、bottom(右下角縱坐標)

注意:這些坐標都是相對于父容器來說的,是一種相對坐標

Top = getTop()Left = getLeft(),Right = getRight(),Bottom=getBottom()

自Anroid3.0后,增加了xytranslationXtranslationY這幾個引數,

  • xyView左上角的坐標
  • translationXtranslationY:左上角相對于父容器的偏移量

注意:View在平移程序中,topleft表示原始左上角的位置資訊,發生改變的值是xytranslationXtranslationY這四個引數,

Q2:getX()getY()getRawX()getRawY()有什么區別?

getXgetY是視圖坐標,是相對于控制元件的距離

getRawXgetRawY是絕對坐標,是與整個螢屏的距離

Q3:View怎么獲取自身的寬和高?

width = getRight()-getLeft() = getWidth()

height = getBottom()-getTop() = getHeight()

2.2.3 View的觸控
2.2.3.1 MotionEvent

手指接觸螢屏后所產生的一系列事件,

  • ACTION_DOWN —— 手指剛接觸螢屏
  • ACTION_MOVE —— 手指在螢屏上移動
  • ACTION_UP —— 手指從螢屏上松開的一瞬間

正常情況下,觸摸螢屏會出現以下兩種情況

  • 點擊螢屏后松開,DOWN -> UP
  • 點擊螢屏滑動后再松開,DOWN->MOVE->…->MOVE->UP
2.2.3.2 TouchSlop

TouchSlop是系統所能識別出的被認為是滑動的最小距離,是一個常量,

Q1:怎么獲取這個常量?

ViewConfiguration.get(getContext()).getScaledTouchSlop()

Q2:這個常量有什么意義?

在處理滑動時,可以利用這個常量來進行過濾,當兩次滑動事件的滑動距離小于這個常量時,可以認為它們不是滑動,

2.2.3.3 VelocityTracker

速度追蹤,用于追蹤手指在滑動程序中的速度,包括水平和豎直速度,

Q:怎么使用VelocityTracker

1.在ViewonTouchEvent方法中追蹤當前點擊事件的速度

 VelocityTracker velocityTracker = VelocityTracker.obtain(); 
 velocityTracker.addMovement(event);

2.獲取當前速度

  velocityTracker.computeCurrentVelocity(1000);
        int xVelocity = (int)velocityTracker.getXVelocity();
        int yVelocity = (int)velocityTracker.getYVelocity();

注意:

  • 獲取速度之前需要先計算速度,即getXVelocity()getYVelocity()方法前必須先呼叫velocityTracker.computeCurrentVelocity(1000);

  • 這里的速度指的事一段時間內手滑動的像素數,速度可以為正也可以為負,因為在Android坐標系中,手指逆著坐標正方向滑動,速度結果就是負的,這里的正負指的是方向,

    速度 = (終點位置 - 起點位置)/時間段

3.使用clear重置并回收記憶體

當不需要使用velocityTracker時,需要使用clear去回收它,

   velocityTracker.clear();
        velocityTracker.recycle();
2.2.3.4 GestureDetector

手勢檢測,用于輔助檢測用戶的單擊、滑動、長按、雙擊等行為,

Q:怎么使用GestureDetector

1.創建一個GestureDetector物件并實作OnGestureDetector介面

 GestureDetector mGestureDetector = new GestureDetector(this,this);
        //解決長按螢屏后無法拖動的現象
  mGestureDetector.setIsLongpressEnabled(false);

2.在ViewonTouchEvent方法添加

 boolean consume = mGestureDetector.onTouchEvent(event);
        return consume;

3.有選擇的實作OnGestureListenerOnDoubleTapListener中的方法

建議:如果只是監聽滑動操作,建議在onTouchEvent中實作;如果要監聽雙擊這種行為,則使用GestureDetector

2.2.3.5 Scroller

彈性滑動物件,用于實作View的彈性滑動

Q:如何使用Scroller?典型代碼固定,如下,

Scroller scroller = new Scroller(mContext);

//緩慢滾動到指定位置
    private void smoothScrollTo(int destX,int destY){
        int scrollX = getScrollX();
        int delta = destX -scrollX;
        //1000ms內滑向destX,效果就是慢慢滑動
        scroller.startScroll(scrollX,0,delta,0,1000);
        invalidate;
    }
    
    @Override
    Public void computeScroll(){
    	if(mScroller.computeScrollOffset()){
    		ScrollTo(mScroll.getCurrX(),mScroller.getCurrY());
    		postInvalidate();
    	}
    }

三、View的滑動

滑動在Android開發中具有重要的作用,掌味訓動的方法是實作自定義控制元件的基礎,

View滑動的基本思想:

當觸摸事件傳到View時,系統記下觸摸點的坐標,手指移動時系統記下移動后的觸摸的坐標并算出偏移量,并通過偏移量來修改View的坐標,

3.1 View滑動的7種方法

3.2.1 layout()

思路:view進行繪制的時候會呼叫onLayout()方法來設定顯示的位置,因此可以通過修改Viewlefttoprightbottom這四種屬性來控制View的坐標,

  • 使用:
 public boolean onTouchEvent(MotionEvent event) {
        //獲取到手指處的橫坐標和縱坐標
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                lastX = x;
                lastY = y;
                break;
            case MotionEvent.ACTION_MOVE:
                //計算移動的距離
                int offsetX = x - lastX;
                int offsetY = y - lastY;
                //呼叫layout方法來重新放置它的位置
                layout(getLeft()+offsetX, getTop()+offsetY,
                        getRight()+offsetX , getBottom()+offsetY); //layout()方法
                break;
        }
        return true;
    }

3.2.2 offsetLeftAndRight()offsetTopAndBottom()

思路:與layout()方法思路一樣,不同的是offsetLeftAndRight()offsetTopAndBottom()方法設定的是左右和上下的偏離值,

使用:

public boolean onTouchEvent(MotionEvent event) {
        //獲取到手指處的橫坐標和縱坐標
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                lastX = x;
                lastY = y;
                break;
            case MotionEvent.ACTION_MOVE:
                //計算移動的距離
                int offsetX = x - lastX;
                int offsetY = y - lastY;
                //對left和right進行偏移
                offsetLeftAndRight(offsetX);  
                //對top和bottom進行偏移
                offsetTopAndBottom(offsetY);
                break;
        }
        return true;
    }
3.2.3 LayoutParams(改變布局引數)

思路:LayoutParams主要保存了一個View的布局引數,可以通過LayoutParams來改變View的布局的引數從而達到了改變View的位置的效果,

  • 使用:
public boolean onTouchEvent(MotionEvent event) {
        //獲取到手指處的橫坐標和縱坐標
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                lastX = x;
                lastY = y;
                break;
            case MotionEvent.ACTION_MOVE:
                //計算移動的距離
                int offsetX = x - lastX;
                int offsetY = y - lastY;
                LinearLayout.LayoutParams layoutParams= (LinearLayout.LayoutParams) getLayoutParams();
                layoutParams.leftMargin = getLeft() + offsetX;
                layoutParams.topMargin = getTop() + offsetY;
                setLayoutParams(layoutParams);
                break;
        }
        return true;
    }

? 父控制元件若是LinearLayout則按代碼上所示,父控制元件若是RelativeLayout,則要使用RelativeLayout.LayoutParams,除了使用布局的LayoutParams外,也可以用ViewGroup.MarginLayoutParams來實作

ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams();

3.2.4 影片

思路:通過影片可以讓一個View進行平移,而平移也就是一種滑動,主要操作的是ViewtranslationXtranslationY屬性,

Android 內有兩種影片可以使用:View影片和屬性影片,

  • View影片使用:

    1.在res目錄新建anim檔案夾并創建translate.xml:

  LinearLayout.LayoutParams layoutParams= (LinearLayout.LayoutParams) getLayoutParams();
                layoutParams.leftMargin = getLeft() + offsetX;
                layoutParams.topMargin = getTop() + offsetY;
                setLayoutParams(layoutParams);

? 2.在Java代碼中參考:

 mCustomView.setAnimation(AnimationUtils.loadAnimation(this, R.anim.translate));

注意:View影片并不能改變View的位置引數,

如果對一個Button進行如上的平移影片操作,當Button平移300像素停留在當前位置時,我們點擊這個Button并不會觸發點擊事件,但在我們點擊這個Button的原始位置時卻觸發了點擊事件,這就是補間影片和屬性影片的區別

  • 屬性影片使用:

    CustomView在1000毫秒內沿著X軸像右平移300像素:

ObjectAnimator.ofFloat(mCustomView,"translationX",0,300).setDuration(1000).start();

3.2.5 scrollTo/scrollBy

思路:scollTo(x,y)表示移動到一個具體的坐標點,而scollBy(dx,dy)則表示移動的增量為dx、dy,其中scollBy最終也是要呼叫scollTo的,scollToscollBy移動的是View的內容,如果在ViewGroup中使用則是移動他所有的子View

  • 使用:
 public boolean onTouchEvent(MotionEvent event) {
        //獲取到手指處的橫坐標和縱坐標
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                lastX = x;
                lastY = y;
                break;
            case MotionEvent.ACTION_MOVE:
                //計算移動的距離
                int offsetX = x - lastX;
                int offsetY = y - lastY;
                ((View)getParent()).scrollBy(-offsetX,-offsetY);
                break;
        }
        return true;
    }

3.2.6 Scroller

scollTo/scollBy方法來進行滑動時,這個程序是瞬間完成的,使用Scroller來實作有過度效果的滑動,這個程序不是瞬間完成的,而是在一定的時間間隔完成的,Scroller本身是不能實作View的滑動的,它需要配合ViewcomputeScroll()方法才能彈性滑動的效果,

  • 使用:
@Override
    public void computeScroll() {
        super.computeScroll();
        if(mScroller.computeScrollOffset()){
            ((View)getParent()).scrollTo(mScroller.getCurrX(),mScroller.getCurrY());
            //不斷的重繪,重復呼叫computeScroll方法
            PostInvalidate();
        }
    }
    //緩慢滾動到指定位置
    public void smoothScrollTo(int destX,int destY){
        int scrollX=getScrollX();
        int delta=destX-scrollX;
        //1000秒內滑向destX
        mScroller.startScroll(scrollX,0,delta,0,2000);
        invalidate();
    }

View類中呼叫

    //使用Scroll來進行平滑移動
          mCustomView.smoothScrollTo(-400,0);
  • 原始碼分析

    當我們構造一個Scroller物件并呼叫它的startScroll方法時,startScroll保存了傳遞的幾個引數

       /**
         * @param startX 起點的橫坐標
         * @param startY 起點的縱坐標
         * @param dx 水平滑動的距離
         * @param dy 豎直滑動的距離
         * @param duration 滑動時間
         */
      public void startScroll(int startX, int startY, int dx, int dy, int duration) {
            mMode = SCROLL_MODE;
            mFinished = false;
            mDuration = duration;
            mStartTime = AnimationUtils.currentAnimationTimeMillis();
            mStartX = startX;
            mStartY = startY;
            mFinalX = startX + dx;
            mFinalY = startY + dy;
            mDeltaX = dx;
            mDeltaY = dy;
            mDurationReciprocal = 1.0f / (float) mDuration;
        }
    

    Q1:在startScroll方法中,內部并沒有做滑動相關的事,那么startScroll是如何讓View滑動的?

    答:使用invalidate方法,invalidate方法會導致View重繪,重繪程序中Viewdraw方法中又會去呼叫computeScroll方法,本來computeScroll方法在View中是一個空實作,在上面的代碼中我們已經添加代碼,通過scrollTo方法實作滑動,接著使用PostInvalidat方法第二次重繪,如此反復,知道整個滑動程序結束,

    computeScroll方法中有使用到computeScrollOffset()方法,下面看看這個方法的原始碼

    public boolean computeScrollOffset() {
            if (mFinished) {
                return false;
            }
    
            int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);
        
            if (timePassed < mDuration) {
                switch (mMode) {
                case SCROLL_MODE:
                    final float x = mInterpolator.getInterpolation(timePassed * mDurationReciprocal);
                    mCurrX = mStartX + Math.round(x * mDeltaX);
                    mCurrY = mStartY + Math.round(x * mDeltaY);
                    break;
      .......              
    

    這個方法會根據時間的流逝計算當前的scrollXscrollY的值,回傳ture時表示滑動未結束,回傳false則表示滑動已結束,

3.2.7 延時策略

核心思想:通過發送一系列延時訊息從而達到一種漸進性效果,

使用:Handle/ViewpostDelayed/執行緒的sleep

注意:無法精確定時,因為系統訊息調度也需要時間,

四、事件分發機制

事件分發機制是View體系里學習的核心點,它是解決滑動沖突的理論基礎,因此,學習好事件分發機制是非常重要的,

這一部分主要是我對知識的總結概括,看了之后還是對事件分發機制感到模糊的讀者,推薦一篇詳細的事件分發文章學習 View 事件分發,就像外地人上了黑車!,

Q1:什么是點擊事件的事件分發?

當一個點擊事件MotionEvent產生以后,系統把這個事件傳遞給具體的View的程序,就是事件分發程序,

4.1 主要方法

  • dispatchTouchEvent:進行事件的分發(傳遞),回傳值是 boolean 型別,受當前onTouchEvent下級viewdispatchTouchEvent影響

  • onInterceptTouchEvent:對事件進行攔截,該方法只在ViewGroup中有,View(不包含 ViewGroup)是沒有的,如果一旦攔截,則執行ViewGrouponTouchEvent,在ViewGroup中處理事件,而不接著分發給View,且只呼叫一次,所以后面的事件都會交給ViewGroup處理,

  • onTouchEvent:進行事件處理,

三者關系的偽代碼:

public boolean dispatchTouchEvent(MotionEvent event) {
        boolean consume  = false; //boolean型別的值表示是否消費事件
        if(onInterceptTouchEvent(event)){ //當前View攔截了這個事件
            consume = onTouchEvent(event); //執行當前View的onTouchEvent()方法,是否消費由該回傳值決定
        }else {//當前View沒有攔截這個事件
            consume  = child.dispatchTouchEvent(event);  //事件傳遞給下一層View的dispatchTouchEvent()方法,是否消費由下一層ViewdispatchTouchEvent()方法回傳值決定
        }
        return consume;
    }

4.2 事件分發的全流程

Q2: View事件分發的本質是什么?

View事件分發的本質是遞回,點擊事件自上而下分發的程序是“遞”,消耗事件自下而上的程序是“歸”,

Q3: “遞”和“歸”的兩個程序分別是什么?

當一個點擊事件產生后,它的傳遞程序會遵循如下順序:Activity->Window->ViewGroup->…->View,這個自上而下傳遞的程序就是“遞“的程序,

當傳遞到具體的一個View后,這個View的onTouchEvent回傳false,即不消耗這個事件,那么這個事件則會向上傳遞,假若所有的元素都不處理這事件,那么這個事件最侄訓傳遞給Activity處理,這個自下而上傳遞的程序就是“歸”的程序,

注意:

在“遞”的程序中,ViewGroup 可以在當前層級,通過設定 onInterceptTouchEvent 方法回傳 true,來攔截事件的下發,而直接步入“歸”流程,

ViewGroup 可以攔截事件下發的同時,child 也可以通過 getParent.requestDisallowInterceptTouchEvent 方法,來阻止上一級的下發攔截,

圖取自學習 View 事件分發,就像外地人上了黑車!

總結:同樣參考上面鏈接

4.3 原始碼分析

事件分發的三個程序:

  1. Activity對事件的分發
  2. 頂級View對事件的分發
  3. View對事件的處理

這里不列出原始碼,僅畫出流程圖,需要查看原始碼的讀者可查看《Android開發藝術探索》相應章節或者在編譯器中查看,

五、滑動沖突

在使用滑動的程序中,假設一種情況,一個界面內外兩層可以滑動,這個時候你滑動它,這個界面怎么判定你滑動的是內層還是外層?這個時候就會產生滑動沖突,所以在這個部分,我們一起來解決這個滑動沖突,

5.1 場景的滑動沖突場景

  • 場景A:外部滑動與內部滑動不一致的滑動沖突,常見于常見于ScrollViewFragmentLisetView的使用,
  • 場景B:外部滑動與內部滑動一致的滑動沖突,可能出現在自定義ViewListView中,外部可以上下滑動,內部也可以上下滑動,
  • 場景C:場景AB的嵌套,

5.2 處理規則

  • 場景A的處理規則:當用戶左右滑動時,讓外部的View攔截點擊事件,當用戶上下滑動時,讓內部的View攔截點擊事件,

    Q1:如何判斷用戶是左右滑動還是上下滑動

    利用水平偏移量和豎直方向的偏移量進行相減,用是否大于0來判斷哪個偏移量大,若偏移量offsetX-offsetY>0,可判斷為水平滑動,這時可以由外部攔截,讓它來處理點擊事件,

  • 場景B的處理規則:需要根據業務邏輯來處理,,規定何時讓外部View攔截事件何時由內部View攔截事件,

  • 場景C的處理規則:同樣需要從業務上找突破點

5.3 解決方法

  • 外部攔截法

  • 內部攔截法

5.3.1 外部攔截法

點擊事件都先經過父容器的攔截處理,如果父容器需要就攔截,不需要此事件就不攔截,

方法:需要重寫父容器的onInterceptTouchEvent方法,在內部做出相應的攔截,

注意:父容器一旦開始攔截任何一個事件,那么后續的事件都會交給它來處理,

//重寫父容器的攔截方法
public boolean onInterceptTouchEvent (MotionEvent event){
    boolean intercepted = false;
    int x = (int) event.getX();
    int y = (int) event.getY();
    switch (event.getAction()) {
      case MotionEvent.ACTION_DOWN://對于ACTION_DOWN事件必須回傳false,一旦攔截后續事件將不能傳遞給子View
         intercepted = false;
         break;
      case MotionEvent.ACTION_MOVE://對于ACTION_MOVE事件根據需要決定是否攔截
         if (父容器需要當前事件) {
             intercepted = true;
         } else {
             intercepted = flase;
         }
         break;
   }
      case MotionEvent.ACTION_UP://對于ACTION_UP事件必須回傳false,一旦攔截子View的onClick事件將不會觸發
         intercepted = false;
         break;
      default : break;
   }
    mLastXIntercept = x;
    mLastYIntercept = y;
    return intercepted;
   }

5.3.2 內部攔截法

父容器不攔截任何事件,所有事件都傳遞個給子元素,如果子元素需要此事件就直接消耗,否則交由父容器處理,

方法:需要配合requestDisallowInterceptTouchEvent方法,重寫子ViewdispatchTouchEvent()

public boolean dispatchTouchEvent ( MotionEvent event ) {
  int x = (int) event.getX();
  int y = (int) event.getY();

  switch (event.getAction) {
      case MotionEvent.ACTION_DOWN:
         parent.requestDisallowInterceptTouchEvent(true);//為true表示禁止父容器攔截
         break;
      case MotionEvent.ACTION_MOVE:
         int deltaX = x - mLastX;
         int deltaY = y - mLastY;
         if (父容器需要此類點擊事件) {
             parent.requestDisallowInterceptTouchEvent(false);//為fasle表示允許父容器攔截
         }
         break;
      case MotionEvent.ACTION_UP:
         break;
      default :
         break;        
 }

  mLastX = x;
  mLastY = y;
  return super.dispatchTouchEvent(event);
}

注意:除子容器需要做處理外,父容器也要默認攔截除了ACTION_DOWN以外的其他事件,這樣當子容器呼叫parent.requestDisallowInterceptTouchEvent(false)方法時,父元素才能繼續攔截所需的事件,

因此,父View需要重寫onInterceptTouchEvent()

public boolean onInterceptTouchEvent (MotionEvent event) {
 int action = event.getAction();
 if(action == MotionEvent.ACTION_DOWN) {
     return false;
 } else {
     return true;
 }
}

Q1:為什么父容器不能攔截ACTION_DOWN事件?

由于該事件并不受FLAG_DISALLOW_INTERCEPT(由requestDisallowInterceptTouchEvent方法設定)標記位控制,所以一旦父容器攔截了該事件,那么所有的事件都不會傳遞給子View,內部攔截法也就失效了,


參考自:

  • 《Android開發藝術探索》

  • 《Android進階之光》

  • 進階之路 | 奇妙的View之旅

  • 學習 View 事件分發,就像外地人上了黑車!

轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/136827.html

標籤:其他

上一篇:Vue UI 創建Vue前端工程(Windows)

下一篇:Android 底部導航欄以及導航欄角標顯示,使用LinearLayout+Fragment實作

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • vue移動端上拉加載

    可能做得過于簡單或者比較low,請各位大佬留情,一起探討技術 ......

    uj5u.com 2020-09-10 04:38:07 more
  • 優美網站首頁,頂部多層導航

    一個個人用的瀏覽器首頁,可以把一下常用的網站放在這里,平常打開會比較方便。 第一步,HTML代碼 <script src=https://www.cnblogs.com/szharf/p/"js/jquery-3.4.1.min.js"></script> <div id="navigate"> <ul> <li class="labels labels_1"> ......

    uj5u.com 2020-09-10 04:38:47 more
  • 頁面為要加<!DOCTYPE html>

    最近因為寫一個js函式,需要用到$(window).height(); 由于手寫demo的時候,過于自信,其實對前端方面的認識也不夠體系,用文本檔案直接敲出來的html代碼,第一行沒有加上<!DOCTYPE html> 導致了$(window).height();的結果直接是整個document的高 ......

    uj5u.com 2020-09-10 04:38:52 more
  • WordPress網站程式手動升級要做好資料備份

    WordPress博客網站程式在進行升級前,必須要做好網站資料的備份,這個問題良家佐言是遇見過的;在剛開始接觸WordPress博客程式的時候,因為升級問題和博客網站的修改的一些嘗試,良家佐言是吃盡了苦頭。因為購買的是西部數碼的空間和域名,每當佐言把自己的WordPress博客網站搞到一塌糊涂的時候 ......

    uj5u.com 2020-09-10 04:39:30 more
  • WordPress程式不能升級為5.4.2版本的原因

    WordPress是一款個人博客系統,受到英文博客愛好者和中文博客愛好者的追捧,并逐步演化成一款內容管理系統軟體;它是使用PHP語言和MySQL資料庫開發的,用戶可以在支持PHP和MySQL資料庫的服務器上使用自己的博客。每一次WordPress程式的更新,就會牽動無數WordPress愛好者的心, ......

    uj5u.com 2020-09-10 04:39:49 more
  • 使用CSS3的偽元素進行首字母下沉和首行改變樣式

    網頁中常見的一種效果,首字改變樣式或者首行改變樣式,效果如下圖。 代碼: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, ......

    uj5u.com 2020-09-10 04:40:09 more
  • 關于a標簽的講解

    什么是a標簽? <a> 標簽定義超鏈接,用于從一個頁面鏈接到另一個頁面。 <a> 元素最重要的屬性是 href 屬性,它指定鏈接的目標。 a標簽的語法格式:<a href=https://www.cnblogs.com/summerxbc/p/"指定要跳轉的目標界面的鏈接">需要展示給用戶看見的內容</a> a標簽 在所有瀏覽器中,鏈接的默認外觀如下: 未被訪問的鏈接帶 ......

    uj5u.com 2020-09-10 04:40:11 more
  • 前端輪播圖

    在需要輪播的頁面是引入swiper.min.js和swiper.min.css swiper.min.js地址: 鏈接:https://pan.baidu.com/s/15Uh516YHa4CV3X-RyjEIWw 提取碼:4aks swiper.min.css地址 鏈接:https://pan.b ......

    uj5u.com 2020-09-10 04:40:13 more
  • 如何設定html中的背景圖片(全屏顯示,且不拉伸)

    1 <style>2 body{background-image:url(https://uploadbeta.com/api/pictures/random/?key=BingEverydayWallpaperPicture); 3 background-size:cover;background ......

    uj5u.com 2020-09-10 04:40:16 more
  • Java學習——HTML詳解(上)

    HTML詳解 初識HTML Hyper Text Markup Language(超文本標記語言) 1 <!--DOCTYPE:告訴瀏覽器我們要使用什么規范--> 2 <!DOCTYPE html> 3 <html lang="en"> 4 <head> 5 <!--meta 描述性的標簽,描述一些 ......

    uj5u.com 2020-09-10 04:40:33 more
最新发布
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 07:59:23 more
  • 生產事故-走近科學之消失的JWT

    入職多年,面對生產環境,盡管都是小心翼翼,慎之又慎,還是難免捅出簍子。輕則滿頭大汗,面紅耳赤。重則系統停擺,損失資金。每一個生產事故的背后,都是寶貴的經驗和教訓,都是專案成員的血淚史。為了更好地防范和遏制今后的各類事故,特開此專題,長期更新和記錄大大小小的各類事故。有些是親身經歷,有些是經人耳傳口授 ......

    uj5u.com 2023-04-18 07:55:04 more
  • 記錄--Canvas實作打飛字游戲

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 打開游戲界面,看到一個畫面簡潔、卻又富有挑戰性的游戲。螢屏上,有一個白色的矩形框,里面不斷下落著各種單詞,而我需要迅速地輸入這些單詞。如果我輸入的單詞與螢屏上的單詞匹配,那么我就可以獲得得分;如果我輸入的單詞錯誤或者時間過長,那么我就會輸 ......

    uj5u.com 2023-04-04 08:35:30 more
  • 了解 HTTP 看這一篇就夠

    在學習網路之前,了解它的歷史能夠幫助我們明白為何它會發展為如今這個樣子,引發探究網路的興趣。下面的這張圖片就展示了“互聯網”誕生至今的發展歷程。 ......

    uj5u.com 2023-03-16 11:00:15 more
  • 藍牙-低功耗中心設備

    //11.開啟藍牙配接器 openBluetoothAdapter //21.開始搜索藍牙設備 startBluetoothDevicesDiscovery //31.開啟監聽搜索藍牙設備 onBluetoothDeviceFound //30.停止監聽搜索藍牙設備 offBluetoothDevi ......

    uj5u.com 2023-03-15 09:06:45 more
  • canvas畫板(滑鼠和觸摸)

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>canves</title> <style> #canvas { cursor:url(../images/pen.png),crosshair; } #canvasdiv{ bo ......

    uj5u.com 2023-02-15 08:56:31 more
  • 手機端H5 實作自定義拍照界面

    手機端 H5 實作自定義拍照界面也可以使用 MediaDevices API 和 <video> 標簽來實作,和在桌面端做法基本一致。 首先,使用 MediaDevices.getUserMedia() 方法獲取攝像頭媒體流,并將其傳遞給 <video> 標簽進行渲染。 接著,使用 HTML 的 < ......

    uj5u.com 2023-01-12 07:58:22 more
  • 記錄--短視頻滑動播放在 H5 下的實作

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 短視頻已經無數不在了,但是主體還是使用 app 來承載的。本文講述 H5 如何實作 app 的視頻滑動體驗。 無聲勝有聲,一圖頂百辯,且看下圖: 網址鏈接(需在微信或者手Q中瀏覽) 從上圖可以看到,我們主要實作的功能也是本文要講解的有: ......

    uj5u.com 2023-01-04 07:29:05 more
  • 一文讀懂 HTTP/1 HTTP/2 HTTP/3

    從 1989 年萬維網(www)誕生,HTTP(HyperText Transfer Protocol)經歷了眾多版本迭代,WebSocket 也在期間萌芽。1991 年 HTTP0.9 被發明。1996 年出現了 HTTP1.0。2015 年 HTTP2 正式發布。2020 年 HTTP3 或能正... ......

    uj5u.com 2022-12-24 06:56:02 more
  • 【HTML基礎篇002】HTML之form表單超詳解

    ??一、form表單是什么

    ??二、form表單的屬性

    ??三、input中的各種Type屬性值

    ??四、標簽 ......

    uj5u.com 2022-12-18 07:17:06 more