package com.zzhoujay.richeditorfunctionbar; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.content.Context; import android.content.DialogInterface; import android.graphics.drawable.Drawable; import android.os.Build; import android.support.v4.content.ContextCompat; import android.support.v7.app.AlertDialog; import android.support.v7.widget.AppCompatImageButton; import android.support.v7.widget.AppCompatSpinner; import android.util.AttributeSet; import android.util.SparseArray; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.EditText; import android.widget.HorizontalScrollView; import com.zzhoujay.richeditor.RichEditor; import com.zzhoujay.richeditor.Style; import com.zzhoujay.richeditor.StyleType; import com.zzhoujay.richeditor.callback.CursorChangeListener; import com.zzhoujay.richeditor.callback.CursorProvider; import com.zzhoujay.richeditor.ext.StyleTypeStateSpec; import java.util.HashSet; /** * Created by zhou on 2016/11/29. * 富文本编辑器功能栏 */ public class RichEditorFunctionBar extends HorizontalScrollView implements CursorChangeListener { private RichEditor richEditor; private CursorProvider cursorProvider; private SparseArray<StateListImageButton> stateListImageButtonSparseArray; private HashSet<Integer> typeSet; private AppCompatSpinner head; public RichEditorFunctionBar(Context context) { super(context); init(context); } public RichEditorFunctionBar(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public RichEditorFunctionBar(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public RichEditorFunctionBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); init(context); } public void setRichEditor(RichEditor richEditor) { this.richEditor = richEditor; } public void setCursorProvider(CursorProvider cursorProvider) { this.cursorProvider = cursorProvider; } private void init(Context context) { setScrollBarStyle(SCROLLBARS_INSIDE_INSET); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { setScrollBarSize(getScrollBarSize() / 2); } @SuppressLint("InflateParams") View view = LayoutInflater.from(context).inflate(R.layout.layout_function_bar, null); LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT); addView(view, params); initView(); initButton(context); } private void initView() { head = (AppCompatSpinner) findViewById(R.id.spinner); head.setAdapter(new SpinnerAdapter()); head.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { if (position == 0) { richEditor.endStyle(StyleType.HEAD); } else { richEditor.startStyle(Style.get(StyleType.HEAD), position); } } @Override public void onNothingSelected(AdapterView<?> parent) { } }); StateListImageButton bold = (StateListImageButton) findViewById(R.id.btn_bold); StateListImageButton italic = (StateListImageButton) findViewById(R.id.btn_italic); StateListImageButton code = (StateListImageButton) findViewById(R.id.btn_code); StateListImageButton underline = (StateListImageButton) findViewById(R.id.btn_underline); StateListImageButton delete = (StateListImageButton) findViewById(R.id.btn_delete); StateListImageButton quote = (StateListImageButton) findViewById(R.id.btn_quote); AppCompatImageButton link = (AppCompatImageButton) findViewById(R.id.btn_link); link.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { String src = null; final int start = cursorProvider.getCursorStart(); final int end = cursorProvider.getCursorEnd(); if (start < end) { src = richEditor.subSequence(start, end).toString(); } createLinkInsertDialog(v.getContext(), new LinkInsertCallback() { @Override public void call(String text, String link) { richEditor.replace(text, start, end); richEditor.startStyleWithRange(Style.get(StyleType.LINK), start, start + text.length(), link); } }, src).show(); } }); stateListImageButtonSparseArray = new SparseArray<>(); typeSet = new HashSet<>(); register(StyleType.BOLD, bold); register(StyleType.ITALIC, italic); register(StyleType.DELETE, delete); register(StyleType.UNDER_LINE, underline); register(StyleType.QUOTE, quote); register(StyleType.CODE, code); } private void register(int type, StateListImageButton button) { stateListImageButtonSparseArray.append(type, button); typeSet.add(type); } private void initButton(Context context) { Drawable normal = ContextCompat.getDrawable(context, R.drawable.bg_normal_shape); Drawable select = ContextCompat.getDrawable(context, R.drawable.bg_select_shape); Drawable highlight = ContextCompat.getDrawable(context, R.drawable.bg_highlight_shap); for (int type : typeSet) { final StateListImageButton stateListImageButton = stateListImageButtonSparseArray.get(type); stateListImageButton.addState(StyleTypeStateSpec.StyleTypeState.STATE_NONE, normal); stateListImageButton.addState(StyleTypeStateSpec.StyleTypeState.STATE_EXIST, select); stateListImageButton.addState(StyleTypeStateSpec.StyleTypeState.STATE_ACTIVE, highlight); stateListImageButton.setOnClickListener(new StateListImageButtonOnClickListener(type)); } } @Override public void cursorChange(int newPosition) { int[] typeStates = richEditor.getStyleTypeState(); resetButtonState(StyleTypeStateSpec.StyleTypeState.STATE_NONE); if (typeStates.length > 0) { for (int typeState : typeStates) { int type = StyleTypeStateSpec.getStyleType(typeState); int state = StyleTypeStateSpec.getState(typeState); if (type == StyleType.HEAD) { int arg1 = StyleTypeStateSpec.getArgs1(typeState); head.setSelection(arg1); } else { StateListImageButton stateListImageButton = stateListImageButtonSparseArray.get(type); if (stateListImageButton != null) { stateListImageButton.setState(state); } } } } } private void resetButtonState(int state) { for (int type : typeSet) { stateListImageButtonSparseArray.get(type).setState(state); } head.setSelection(0); } private class StateListImageButtonOnClickListener implements OnClickListener { private int type; StateListImageButtonOnClickListener(int type) { this.type = type; } @Override public void onClick(View v) { StateListImageButton stateListImageButton = ((StateListImageButton) v); int state = stateListImageButton.getState(); if (state == StyleTypeStateSpec.StyleTypeState.STATE_NONE) { stateListImageButton.setState(richEditor.startStyle(type)); } else if (state == StyleTypeStateSpec.StyleTypeState.STATE_ACTIVE) { stateListImageButton.setState(richEditor.endStyle(type)); } else if (state == StyleTypeStateSpec.StyleTypeState.STATE_EXIST) { stateListImageButton.setState(richEditor.endStyle(type)); } } } private interface LinkInsertCallback { void call(String text, String link); } private AlertDialog createLinkInsertDialog(Context context, final LinkInsertCallback callback, String src) { AlertDialog.Builder builder = new AlertDialog.Builder(context); View view = LayoutInflater.from(context).inflate(R.layout.layout_link_insert, null); final EditText text = (EditText) view.findViewById(R.id.dialog_edit_1); final EditText link = (EditText) view.findViewById(R.id.dialog_edit_2); if (src != null) { text.setText(src); } builder.setTitle("Insert Link").setIcon(R.drawable.ic_link).setView(view) .setPositiveButton("insert", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { String t = text.getText().toString(); String l = link.getText().toString(); if (callback != null) { callback.call(t, l); } } }).setNegativeButton("cancel", null); return builder.create(); } }