Android 모방 웨 이 보 @ 친구, \ # 화제 \ # 및 links 처리 방안

개술
웨 이 보 를 사용 할 때 우 리 는 모두 이 두 가지 기능 을 발견 할 것 이다.
  • EditText 입력 가능 @ , # # 및 링크 links
  • 동태 중 전시 가능 @ , # # 및 링크 links
  • Span 를 통 해 이 루어 졌 다 고 생각 하기 쉽 지만 그 중에서 세부 적 인 처리 가 필요 하 다.
    EditText
    입력 부분의 세부 기능
  • 키워드 변색 하 이 라이트
  • 삭제 할 때 전체 삭 제 를 선택 하 십시오
  • 초점 및 커서 가 키워드 중간 에 떨 어 지면 안 됩 니 다
  • 보통 부가 정보 가 있 습 니 다
  • 마지막 으로 다음 과 같은 고려 를 바탕 으로 한다. 예 를 들 어 ,id 일반적으로 이와 같은 처리, @ 또는 (@ ,id=xxx)서로 다른 id, 점프 인터페이스, 예 를 들 어 사용자 상세 페이지 .
    참조 구현:
  • 시 나 웨 이 보 가 # 화 제 를 모방 한 EditText 실현
  • luckyandyzhang/MentionEditText

  • 최적화 실현
    마지막 으로 MentionEditText 에 대해 최 적 화 를 했 습 니 다. 소스 코드: Mentions 중의 EditText 부분 입 니 다.추상 적 인 그 기능 은 주로 이 몇 가지 측면 과 관련된다.
  • 인터페이스 에 표 시 된 CharSequence
  • 추가 필드 가 있 는 CharSequence
  • 하 이 라이트 컬러
  • 먼저 용법 을 보고 실현 을 봅 시다.
  • User
  • public class User implements InsertData{
      //...
    
      @Override public CharSequence charSequence() {
          return "@"+userName; //provide the CharSequence insert to edittext
        }
    
        @Override public FormatRange.FormatData formatData() {
          return new UserConvert(this);//provide the formater for the insert data
        }
    
        @Override public int color() {
          return Color.MAGENTA;//provide the range color
        }
    
        private class UserConvert implements FormatRange.FormatData {
    
          public static final String USER_FORMART = "(@%s,id=%s)";
          private final User user;
    
          public UserConvert(User user) {
            this.user = user;
          }
    
          @Override public CharSequence formatCharSequence() {//format
            return String.format(USER_FORMART, user.getUserName(), user.getUserId());
          }
        }
    }
  • Activity
  • public class MainActivity extends AppCompatActivity{
    @BindView(R.id.mentionedittext) MentionEditText mMentionedittext;
    @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    
        if (resultCode == Activity.RESULT_OK && null != data) {
          switch (requestCode) {
            case REQUEST_USER_APPEND:
              User user = (User) data.getSerializableExtra(UserList.RESULT_USER);
              mMentionedittext.insert(user);//insert data to edittext
              break;
            //...
          }
        }
    
        super.onActivityResult(requestCode, resultCode, data);
      }
    }
  • 서버 에 보 낸 데이터 가 져 오기
  • CharSequence convertMetionString = mMentionedittext.getFormatCharSequence();//      format  ,      (@xxx,id=xxx-xx-x)

    다음은 실현.
    !. 우 리 는 먼저 인 터 페 이 스 를 제공 하고 삽 입 된 데 이 터 를 정의 합 니 다. 다음 과 같 습 니 다.
    public interface InsertData {
    
      CharSequence charSequence(); //       CharSequence
    
      FormatRange.FormatData formatData();//  CharSequence    
    
      int color();//         
    }

    !!. 왜 이 인 터 페 이 스 를 정의 합 니까? 먼저 문자 의 삽입 과정 을 보 세 요.
    //    
    public void insert(InsertData insertData) {
    //1.           CharSequence
    //2.    CharSequence            
    //3.      
        }
      }

    위 와 같이 두 번 째 단계 에서 필요 한 정 보 는 문자 의 시작 위치, 문자, 전환 후의 문 자 를 포함 할 수 있 습 니 다. 그러나 뒤에 문자 , 그리고 (서로 다른 전환 을 거 쳐 야 할 수도 있 습 니 다) 는 하나의 컨버터 를 제공 하여 사용자 가 스스로 실현 하도록 합 니 다.
    !!!. 그래서 인터페이스 가 바 뀌 었 습 니 다. 다음 과 같 습 니 다.
      public interface FormatData {
    
        CharSequence formatCharSequence();//          CharSequence
      }

    !!!!. 그러면 위의 삽입 코드 는 다음 과 같은 방식 으로 쓸 수 있다.
    public void insert(InsertData insertData) {
        if (null != insertData) {
          CharSequence charSequence = insertData.charSequence();
          Editable editable = getText();
          int start = getSelectionStart();//         
          int end = start + charSequence.length();//      
          editable.insert(start, charSequence);//  
          FormatRange.FormatData format = insertData.formatData();
          Range range = new FormatRange(start, end, format);
          mRangeManager.add(range);//         ,        
    
          int color = insertData.color();
          editable.setSpan(new ForegroundColorSpan(color), start, end,
              Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);//     
        }
      }

    !!!!!. 그러면 위 에 있 는 것들 이 우리 가 원 하 는 최종 정보 로 어떻게 조합 되 는 지 살 펴 보 자. 위 에 Range 정 보 를 저장 했다. 여기 서 이 를 연결 하면 우리 가 원 하 는 정 보 를 구성 할 수 있다. 다음 과 같다.
    // mRangeManager    ArrayList
     public CharSequence getFormatCharSequence(String text) {
        if (isEmpty()) {
          return text;
        }
    
        int lastRangeTo = 0;
        ArrayList extends Range> ranges = get();
        Collections.sort(ranges);//Range    Comparable,     start   
    
        StringBuilder builder = new StringBuilder("");
        CharSequence newChar;
        for (Range range : ranges) {
          if (range instanceof FormatRange) {
            FormatRange formatRange = (FormatRange) range;
            FormatRange.FormatData convert = formatRange.getConvert();
            newChar = convert.formatCharSequence();
            builder.append(text.substring(lastRangeTo, range.getFrom()));//     `Range`          
            builder.append(newChar); //            
            lastRangeTo = range.getTo();
          }
        }
    
        builder.append(text.substring(lastRangeTo));//       `Range`      
        return builder.toString();
      }

    위 와 같이 기능 을 실현 하 였 다.
    TextView
    보 낸 데이터 구조 가 바 뀌 었 기 때문에 전시 할 때 도 상응 한 처 리 를 해 야 한다.
  • 인터페이스 가 나타 나 지 않 고 류 의 실현
  • 을 모방 할 수 있다.
  • 클릭 Html 시 추가 정보 획득 Span 정보 획득 xml
  • 클릭 Attribute 이외 의 곳 에서 해당 사건 에 응답 합 니 다. 여기 구덩이 가 있 습 니 다. Span 사건 을 차단 합 니 다
  • 그림 과 글 혼합 LinkMovementMethod, 지원 emoji, 사용 ellipseSpanableString 효력 을 상실 합 니 다.

  • 참조 구현:
  • TextView Clickable Span 사건 이 배포 한 두 개의 구덩이
  • 제 가 안 드 로 이 드 개발 에서 만난 구덩이 의 웨 이 보 본문 클릭 처리
  • dinuscxj/EllipsizeTextView

  • 최적화 실현:
    사실 앞의 ellipse 에 비해 이것 은 상대 적 으로 훨씬 간단 하 다.
    !. 우선 인터페이스 정의:
    public interface ParserConverter {
    
      Spanned convert(CharSequence source);// CharSequence        Spanned,   Html.fromHtml()
    }

    !!. EditText 계승 MentionTextView, 인터페이스 로 전환
    public class MentionTextView extends TextView {
    //...
    @Override public void setText(CharSequence text, BufferType type) {
        if (!TextUtils.isEmpty(text) && null != mParserConverter) {
          text = mParserConverter.convert(text);
        }
        super.setText(text, type);
        setMovementMethod(new LinkMovementMethod());
      }
      //...
    }

    !!!. 쓰다
    mMentiontextview.setParserConverter(mUserParser);
    CharSequence convertMetionString = mMentionedittext.getFormatCharSequence();
    mMentiontextview.setText(convertMetionString);

    !!! Parser 구현
    먼저 우리 의 TextView 실현 해 야 할 기능 은 다음 과 같다.
  • @ 기능
  • \ # tag \ # 기능
  • links 기능: 예 를 들 어 웨 이 보가 Parserhttp 로 교체 하고 점프 할 수 있다
  • 단계 1.
    public class LinkUtil {
    //       ,    
      private static final Pattern URL_PATTERN = Pattern.compile(
          "((http|https|ftp|ftps):\\/\\/)?([a-zA-Z0-9-]+\\.){1,5}(com|cn|net|org|hk|tw)((\\/(\\w|-)+(\\.([a-zA-Z]+))?)+)?(\\/)?(\\??([\\.%:a-zA-Z0-9_-]+=[#\\.%:a-zA-Z0-9_-]+(&)?)+)?");
    
      public static String replaceUrl(String source) {
        Matcher matcher = URL_PATTERN.matcher(source);
        if (matcher.find()) {
          String url = matcher.group();
    
          source = source.replace(url, ""\'" + url + "\'" + ">    ");
        }
        return source;
      }
    }

    단계 2:
    public class Parser implements ParserConverter {
    
      public Parser() {
      }
    
      @Override public Spanned convert(CharSequence source) {
        if (TextUtils.isEmpty(source)) return new SpannableString("");
        String sourceString = source.toString();
        sourceString = LinkUtil.replaceUrl(sourceString);
    
        return Html.fromHtml(sourceString, null, new HtmlTagHandler());
      }
    }

    위 와 같이 기능 실현, 상세 코드 참조: Mentions

    좋은 웹페이지 즐겨찾기